2. 절차지향 vs 객체지향
난 c언어 부터 시작을 했다.
c언어의 장점
1)문제 해결을 위한 프로그래밍 언어로써 최적이다. (키워드가 32개…)
2)컴퓨터와 가깝다 보니 공부하면서 os , 메모리 동작 방식 이해
3)다들 c언어 부터 시작하니까… (자료가 많다)
4)난 리눅스 빠돌이….
3. 절차지향 vs 객체지향
공부하면서 객체지향을 배워야 하나 ??
의문이 들음
1)그 당시 c언어로 충분하다고 생각
2)첫 언어를 공부하다 보면 거기에 빠돌이가 된다. (다른 언어 배척..)
3)객체 지향에 대한 코드 복잡도 (지금도 그렇지만 객체지향 프로그래밍을 잘
못 짜면 절차지향 언어 보다도 못하다)
4)나중에 알고보니 사실 전문가는 절차지향 이든 객체지향이든 뭐든지 잘한다.
4. 절차지향 vs 객체지향
업무가 들어왔다.
외부 업체에서 계산기 API 를 만들어 달라 한다.
기능)
더하기, 빼기, 곱하기, 나누기
ㅋㅋ 별거없네..
5. 절차지향 vs 객체지향
void add(int n1, int n2)
{
printf("add result: %dn", n1+n2);
}
void sub(int n1, int n2)
{
printf("sub result: %dn", n1-n2);
}
void mul(int n1, int n2)
{
printf("mul result: %dn", n1*n2);
}
void div(int n1, int n2)
{
printf("div result: %dn", n1/n2);
}
6. 절차지향 vs 객체지향
void add(int n1, int n2)
{
printf("add result: %dn", n1+n2);
}
void sub(int n1, int n2)
{
printf("sub result: %dn", n1-n2);
}
void mul(int n1, int n2)
{
printf("mul result: %dn", n1*n2);
}
void div(int n1, int n2)
{
printf("div result: %dn", n1/n2);
}
4개의 함수를 제공
객체지향을 왜 쓰는지 목적을 가지고 있으므로
고민한번 해보자
뭘 고쳤으면 하는가..
이 정도면 된거 아닌가?
7. 절차지향 vs 객체지향
void calculator(int func, int n1, int n2)
{
switch(func)
{
case 0:
add(n1, n2);
break;
case 1:
sub(n1, n2);
break;
case 2:
mul(n1, n2);
break;
case 3:
div(n1, n2);
break;
default:
break;
}
8. 절차지향 vs 객체지향
void calculator(int func, int n1, int n2)
{
switch(func)
{
case 0:
add(n1, n2);
break;
case 1:
sub(n1, n2);
break;
case 2:
mul(n1, n2);
break;
case 3:
div(n1, n2);
break;
default:
break;
}
}
이 정도면 계산기 API
일단 함수 하나로 묶긴 했는데 …
이정도면 업체에 보낼 수 있겟군..
문제점??
근데 업체에서 func 인자가 어떻게 사용되는지
알아야 한다.
10. 절차지향 vs 객체지향
typedef struct Calculator
{
void (*add)(int, int);
void (*sub)(int, int);
void (*mul)(int, int);
void (*div)(int, int);
}Cal;
int main(void) {
Cal c;
c.add = add;
c.sub = sub;
c.mul = mul;
c.div = div;
c.add(1,3);
return 0;
}
계산기 구조체를 만든다
구조체 안에는
덧셈, 뺄셈, 곱셈, 나눗셈 기능이 들어가 있다.
구조체를 초기화 (함수 포인터)
확실히 의미가 명확해 졌다.
그럼 업체에 API 전달 해야지.
11. 절차지향 vs 객체지향
다시 정리 해보자
업체에서 그러면 API 를 쓸때
1. 구조체 생성.
2. 구조체 초기화 (함수 포인터 연결)
유지 보수 생각한번 해보자
계산기 기능 추가시 우리는 함수를 구현후 구조체 함수포인터를 만들며 초기화 작업을 해줘야 한다.
C언어의 구현방식 모습이 보인다.
절차지향 언어의 특징은 동작 에 촛점이 맞추어져 있다.
그래서 개발 방식도 Top Down 방식이다. (위로 부터 구현)
개발을 어느 정도 해보니 공통적으로 나타나는 현상이 있다.
기능에 대한 구현은 항시 DATA 를 조작해야 한다
절차지향에서는 구현에 촛점이 맞춰있어 DATA 는 LOAD 개념으로 접근한다.
(물론 쩌는 프로그래머는 C언어로 해도 구현이 쩐다…. )
기능 을 목적으로 하지 말고 객체 단위로 바라보자.
12. 절차지향 vs 객체지향
void Calculator(char op, int num1, int num2)
{
switch(op)
{
case '+':
cout << num1+num2;
break;
case '-':
cout << num1-num2;
break;
case '*':
cout << num1*num2;
break;
case '/':
cout << num1/num2;
break;
default:
break;
}
}
13. 절차지향 vs 객체지향
void Calculator(char op, int num1, int num2)
{
switch(op)
{
case '+':
cout << num1+num2;
break;
case '-':
cout << num1-num2;
break;
case '*':
cout << num1*num2;
break;
case '/':
cout << num1/num2;
break;
default:
break;
}
}
이 코드 구글에서 검색해서 나온 코드이다.
기능을 중점으로 짜면 절차지향 프로그래밍과
다름이 없다.
객체지향 만능을 이야기 하는 것이 아니다.
모든 언어는 언어가 탄생한 배경에 맞게 써야 한
다.
언어의 철학과 탄생배경을 꼭 이해 하도록 하자.
14. 절차지향 vs 객체지향
class Calculator
{
public:
void add(int n1, int n2);
void sub(int n1, int n2);
void mul(int n1, int n2);
void div(int n1, int n2);
};
int main()
{
Calculator C = new Calculator;
C.add(1, 3);
}
15. 절차지향 vs 객체지향
class Calculator
{
public:
void add(int n1, int n2);
void sub(int n1, int n2);
void mul(int n1, int n2);
void div(int n1, int n2);
};
int main()
{
Calculator C = new Calculator;
C.add(1, 3);
}
계산기라는 객체로 바라보는 것이다.
c언어 구현의 중점은
계산기의 기능을 바라보는 것이다.
사실 계산기로만 보면 별 차이 못느낄수 있지만
개념에 대한 이해를 하면 어렵게 느끼지 않을 것
이다.
16. 절차지향 vs 객체지향
typedef struct _ST_STRBUF
{
int m_nLen; // 스트링 길이
char* m_pStr; // 스트링 데이터 힙메모리 주소
}ST_STRBUF;
// a_nStrLen만큼 a_pstStr 구조체를 초기화한다
int mystr_new(ST_STRBUF* a_pstStr, int a_nStrLen);
// 문자열 a_pStr을 a_pstStr의 문자열에 할당한다
int mystr_assign(ST_STRBUF* a_pstStr, char* a_pStr);
// 문자열a_pStr를 a_pstStr문자열 뒤에 붙인다
int mystr_append(ST_STRBUF* a_ptrStr, char* a_pStr);
// 문자a_chFind를 a_pstStr에서 찾는다
int mystr_find(ST_STRBUF* a_pstStr, char a_chFind);
// a_pstStr를 삭제한다
int mystr_delete(ST_STRBUF* a_pstStr);
17. 절차지향 vs 객체지향
int main()
{
ST_STRBUF stStrBuf = { 0, };
mystr_new(&stStrBuf, 256);
// 초기화를 안한다면 아래호출되는 모든 함수는 오동작 할
것이다.
mystr_assign(&stStrBuf, "abc");
mystr_append(&stStrBuf, "def");
// mystr_assign을 먼저 호출하지 않았다면 오동작 할 것이
다.
// 2번째 파라미터가 문자가 아닐 경우 오동작 할수 있다.
// 문자인지 판단하는 함수가 필요하다
mystr_find(&stStrBuf, 'd');
mystr_delete(&stStrBuf);
return 0;
위 소스에 혹시나 발생할 수 있는 오동작 가능성에 대해
적어 보았다.
실제 개발을 하다 보면 에러 처리를 위해 코드의 덩치가
커지는 경우 가 많다
이런 경우 모든 예외 상황에 맞추어 함수를 하나씩 늘려
가다 보면
어떤 함수를 어떤 경우에 호출해야 하는지를 판단하는 것
조차 어렵다.
사실 아래 코드를 누가 실수를 하겠는가... (초보는 제
외...)
하지만 과연 몇만줄의 코드중 아래의 코드를
작성하다 보면
과연 아래의 빠진 부분이 보일까...
18. 절차지향 vs 객체지향
class CMyString
{
public:
int Assign(char* a_pStr);
int Append(char* a_pStr);
int Find(char a_chFind);
public:
CMyString(int a_nSize);
~CMyString();
private:
int m_nLen;
char* m_pStr;
};
int main()
{
CMyString str(256);
str.Assign("abc");
str.Assign("def");
str.Find('d');
return 0;
}
c언어 코드와 비교해 보면 명확해졌다.
즉 어떤 함수를 호출해야 하는지 헷갈릴 가능성
이 줄어 들었다.
(없다는 뜻이 아니다.)
1) 생성자, 소멸자 활용. (heap 자동화)
2) private 변수 외부 접근불가.
19. 절차지향 vs 객체지향
정리
1)data 와 기능은 분리될수가 없다.
2)절차지향 프로그래밍의 핵심은 기능
3)객체지향의 핵심은 데이터
4)서로 바라보는 관점이 다르다
5)객체지향은 bottom UP 프로그래밍에 적합하다.
6)사실 객체든 절차지향이든 결국엔 외부api 가 되었든 오픈소스이든
누군가에게 보여줄수 있는 코드를 만드는게 목적이며 그렇게 프로그래밍을 해야한
20. DLC 상태캡슐화
솔이가 콜라를 먹는다.
생각나는 대로 코딩해 보자.
Human Sol;
Sol->Drink(Coke); // ??
현실 세계의 객체와 객체지향 세계의 객체 사이에는 중요한 차이점이 있다.
현실속에서는 솔이는 스스로 음료를 마시는 능동적인 존재지만 콜라는 스스로
아무것도 못하는 수동적인 존재이다.
21. DLC 상태캡슐화
그러나 객체지향의 세계에서 모든 객체는 자신의 상태를 스스로 관리하는
자율적인 존재이다. 콜라 객체의 양을 줄이는 건 콜라 객체 자신이 되어야 한다.
따라서 솔이는 콜라의 음료의 양을 줄일 수 없다.
할수 있는건 솔이가 콜라에게 자신이 콜라를 먹었다라는 메세지를 전달할 뿐이다.
음료의 양을 줄이는건 전적으로 콜라의 몫이다.
이것이 캡슐화…
이렇게 작성한 나도 지키지 못하는 경우가 많네…..