SOLID 개념

유혜정·2022년 4월 11일
0

객체 지향 개발을 위한 기본 개념

  1. 단일 책임의 원칙
  • 책임이 1개여야 함
  1. 열림 닫힘의 원칙
  • 상속하면서 확장할 때 기존은 닫히고, 새로운 기능은 열려야 함
  1. 리스코브 치환의 원칙
  2. 인터페이스 분리 원칙
  3. 의존성 역전 원칙

https://www.nextree.co.kr/p6960/

2번 + 4번 + 5번 -> 프레임웍

#include <iostream>
using namespace std;

class Cat {
public:
    void cat_speak() {
        cout << "야옹~~" <<endl;
    }
};
class Dog {
public:
    void dog_speak() {
        cout << "멍멍~~" <<endl;
    }
};
class Cow { // 추가함
public:
    void cow_speak() {
        cout << "음머~~" <<endl;
    }
};

class Zoo {
private:
    Cat cat;
    Dog dog;
    Cow cow; //추가함
public:
    void speak(){
        cat.cat_speak();
        dog.dog_speak();
        cow.cow_speak(); //추가함
    }
};
int main(){
    Zoo zoo;
    zoo.speak();
}
int main(int argc, char** argv){
	int a = 10;
    int b = 20;
    int sum;
    // 컴파일 타임 : 컨파일 하는 시간
    // 런타임 : 실행되면서 걸리는 시간
    sum = 10 + 20; // 정적인 코드 : 컨파일 타임
    sum = a + b; // 정적인 코드
    
    // 속성 - 디버깅 - 명령인수 - '10, 20' 필요함
    // argv[0] : 파일명
    int a2 = atoi(argv[1]);
    int b2 = atoi(argv[2]);
    sum = a2 + b2; // 런타임 코드 계산
    cout << a2 << " + " << b2 << " = " << sum << endl;
}
// cmd에서 입력 방법
// [파일명].exe 10 20

컴파일러가 실수하는 것을 알려줌

int add(const int a, const int b){
	return a+b;
}

int main() {
	int a = 10;
    int b = 20;
    int sum;
    
    sum = add(a, b); // 런타임 코드 계산
	// debug mode -> 함수로 정상 동작함 : runtime 시 계산함
    // release mode -> 최적화로 정적코드로 동작함 (sum = 30)
}

release mode

  • 최적화 한 상황
  • 시간이 더 오래걸림
  • debug에서 안나던 오류가 발생할 수 있음

debug mode

  • 개발하는 상황
  • 시간이 더 빠름
  • 디버깅 정보가 결과물 안에 포함됨

생성(exe 만들기) : 일반적인 경우 debug모드가 exe 생성시 좀더 빠르다
실행 : 일반적으로 release 모드의 결과물이 빠르다
크기 : debug 모드가 크다. release 모드가 보통 debug 모드 대비 1/4 정도 작다.

도구 - 옵션 - 프로젝트 및 솔루션 - vc++ 프로젝트 설정 - 빌드 타이밍 - 예
->> 다시 빌드 진행

  • 빌드 : 수정된 소스만 다시 빌드
  • 다시 빌드 : 처음부터 다시 진행

포인터

일반화 : sum = a + b;
특별화 : sum = 10 + 20;

data pointer

int main() {
	int a = 10;
	int b = 20;
	int c = 10;
	int d = 20;
	sum = a + b; // 변수명에 대해서 특별화
	sum = c + d; // 변수명에 대해서 특별화
    
    p1 = &a;
    p2 = &b;
    sum = *p1 + *p2;
    p1 = &c;
    p2 = &d;
    sum = *p1 + *p2;
    // 일반화 : 외형적으로 같지만, 실행되는 내용이 다름
    // 일반화는 대부분 포인터로 사용할 수 밖에 없음
}

포인터 사용 이유

  • 특별한 변수명에 의한 종속성을 없애기 위함
  • 특별화 -> 일반화

funtion pointer

  • 코딩 로직을 위한 포인터 사용
// typedef oldType newType;
typedef unsigned int UINT;
// typedef type 변수명 : type을 새로운 변수명으로 정의

// int (*)(const int, const int); // 함수 포인터
typedef int (*FP_CALC)(const int, const int); // 함수 포인터 재정의
FP_CALC calc; // calc : 포인트 변수명


// c style
int add(const int a, const int b){
	return a+b;
}
int sub(const int a, const int b){
	return a-b;
}

class Calc{
public:
	virtual int calc(const int a, const int b) = 0;
};
class AddCalc : public Calc {
public:
	virtual int calc(const int a, const int b) override {
    	return a + b;
    }
};
class SubCalc : public Calc {
public:
	virtual int calc(const int a, const int b) override {
    	return a - b;
    }
};
class MulCalc : public Calc {
public:
	virtual int calc(const int a, const int b) override {
    	return a * b;
    }
};
// c style
int MyCalc(Calc& obj, const int a, const int b){
	// 변경되는 것 없음. 새로운 기능 자연스럽게 실행할 수 있음 >> OCP
	return obj.calc(a, b);
}

int main() {
	// c style
	result = add(a, b); // add 함수 : 컴파일 때 결정되는 함수
	result = sub(a, b);
	// 함수명에 대해서 특별화
    
   	calc = add;
    result = calc(a, b); // 실행 중에 결졍(그 윗줄에서 정의되는 함수에 따라 달라짐)
    calc = sub;
    result = calc(a, b);
    
    // cpp style
    Calc* pCalc = new AddCalc();
    result = pCalc->calc(a, b); // a+b
    delete pCalc;
    
    pCalc = new SubCalc();
    result = pCalc->calc(a, b); // a-b
    delete pCalc;
    
    AddCalc addCalc;
    Calc& objA = addCalc;
    result objA.calc(a, b);
    
    SubCalc subCalc;
    Calc& objB = subCalc;
    result objB.calc(a, b);
    
    // c style
    result = MyCalc(addCalc, a, b); // MyCalc가 고정했을 때 일반화
    result = MyCalc(subCalc, a, b);
    
    // 새롭게 추가된 부분
    MulCalc mulCalc;
    result = MyCalc(mulCalc, a, b);
    // 기존의 코드를 변경하지 않음
    
    vector<Calc*> arr = {&addCalc, &subCalc, &mulCalc};
    					// 전달해주는 순서에 따라 달라짐
    /*for(int i = 0;i<arr.size();i++) { // 옛날 방식
    	MyCalc(*arr[i], a, b); // 런타임에 의해 결정
	}*/
    for(auto& pCalc : arr) { // 요즘 방식
    	MyCalc(*pCalc, a, b);
	}
    

}

함수 포인터 재정의 후 사용
OCP에 대하여 설명!!! 확인해보기!!

  • 상속과 virtual function 때문에 가능함

기존 그림 : Direct


확장성 고려된 그림 : Indirect

#include <iostream>
using namespace std;

class Animal {
public:
	virtual void speak() const = 0;
    // const 안써주면 구문오류 발생! >> 테스팅 해보기
};

class Cat : public Animal {
public:
    virtual void speak() const override {
    // virtual 과 override 도 약속처럼 써주기
        cout << "야옹~~" <<endl;
    }
};
class Dog : public Animal {
public:
    virtual void speak() const override {
        cout << "멍멍~~" <<endl;
    }
};
class Cow : public Animal { // 추가함
public:
    virtual void speak() const override {
        cout << "음머~~" <<endl;
    }
};

class Zoo {
private:
	vector<Animal*> array; // 추가하는 함수 필요
public:
	void addAnimal(const Animal* const pAnimal) {
    	// pAnimal++; // 구문 오류를 위해 인자를 const로 선언
        // 포인터 변수를 이용해서 포인터를 변경하면 컴파일 오류를 발생하게 설정
        
    	array.push_back(pAnimal);
    }
    void speak(){
    	for(const auto& pAnimal : array) {
        // 읽기 전용이므로 const로 선언
        	pAnimal->speak();
        }
    }
};
int main(){
    Zoo zoo;
    Cat cat;
    Dog dog;
    Cow cow;
    
    zoo.addAnimal(&cat);
    zoo.addAnimal(&dog);
    zoo.addAnimal(&cow); // 추가함
    // 기존 내용 변경 없이 추가 가능
    
    zoo.speak();
    return 0;
}

프레임웍 버전

  • 기존 라이브러리 사용 + 나의 기능 추가 (main()의 작성은 내가) -> 응용프로그램 작성
BOOL InitInstance(Zoo* pZoo) {
    Zoo zoo;
    Cat cat;
    Dog dog;
    Cow cow;
    
    zoo.addAnimal(&cat);
    zoo.addAnimal(&dog);
    zoo.addAnimal(&cow);
	return TRUE;
}

BOOL Run(Zoo* pZoo) {
    pzoo->speak();
	return TRUE;
}

BOOL ExitInstance(Zoo* pZoo) {
	return TRUE;
}

int main(){
    Zoo zoo;
    
    InitInstance(&zoo);
    // InitInstance 내부만 수정하면 프로그램 변경 가능
    
    Run(&zoo);
    
    ExitInstance(&zoo);
    
    return 0;
}
// 프레임웍 : 사전에 약속된 내용을 지키면서 프로그램 수정 진행

MFC는 위와 같이 하나의 function만 수정하면 가능
기존 c/c++ 처럼 main()을 수정해야 하는 것이 아님

profile
내가 시작한 공부, 공유할 코드

0개의 댓글

관련 채용 정보