BOOKS

코딩의 기술

파란실버라이트 2017. 8. 29. 15:03

1. 읽기 좋은 코드를 작성하는 기술

    • 결정문의 사용해서 If 문을 제거 /  예상 값을 배열에 9까지 경우의 수로 저장해서 해결 . 재미 있네. 

enum Hand {

Rock = 0,

Scissors = 1,

Paper =  2

};


enum Result {

Win,

Lose,

Draw

};


Result judgement(Hand my, Hand target){

if (my ==target) return Draw:

if (my == Rock && target == Scissors) return Win ; 

if (my == Scissors && target == Paper) return Win ; 

if (my == Paper && target == Rock) return Win ; 

return Lose;

}


Result judgment(Hand my, Hand target){


static const Result result[3][3] = {

//바위 , 가위 보 (상대방)

{Draw, Win, Lose }. // 바위(자신)

{Lose, Draw, Win }, // 가위

{Win, Lose, Draw }  // 보 

};

return result[my][target];

}


2. 간단한 설계를 위한 원칙과 패턴

    • 직접하지 말고 명령하라. /위임하라. 
    • 상속보다는 이양을 사용 / Template pattern => Strategy pattern

// 상속으로 설계 

Class Robot {

public update(){}

public move(){}

}


Class CleanRobot : public Robot{

virtual void move() override {}

}

Class CombatRobot : public Robot{

virtual void move() override {}

}



// 위양으로 설계

Class Robot {

RoboBehavior* behavior_;


// Creator

Robot(RobotBehavior* behavior) :

behavior_ (behavior} {}


void update()

{

behavior_->move();

}

}


// Robot Behavior interface , Strategy pattern

Class RobotBehavior {

virtual void move()

};


class CleanerBehavior : public RobotBehavior {

virtual void move() override{

//clean

}

}


class CombatBehavior : public RobotBehavior {

virtual void move() override{

//battle

}

}


// Create Instance

Robot cleanerRobot(new CleanerBehavior());

Robot combatRobot(new CombatBehaviro());


    • 상속 관계는 '컴파일할 때 결함' 합니다. 실행 중에는 구현 객체를 변경하지 못한다. 
    • 이양을 사용하면 실행 중에도 구현 객체를 변경할 수 있다. 
 //Change behavior
ClearnerRobot.changeBehavior(new combatBehavior());

  • 다른 유형의 로봇클래스를 만들고 싶을 때로 행동과 관련한 플래스를 재사용할 수 있다.
// create super robot and reuse behaviro
SuperRobot superRobot(new combatBehavior());
 
    • 상속은 부모 클래스로부터 '기능상혹'을 의미하지만 , 추상 인터페이스는 '역할 구현'을 의미한다. 


3. 객체 지향 설계의 원칙

    1. 단일 책임의 원칙(SRT, Single Responsibility Principle)  - 클래스를 변경해야 되는 이유는 한가지
    2. 개방. 폐쇠의 원칙(OCP, Open-closed principle) - 확장에 관해서는 열려있고, 변경에 대해서 닫여있다.
    3. 리스코프 치환 원칙 (LSB, Liskov Substitution Principle) - 부모를 클래스로 치환한 상태에서도 정상 작동해야 한다. 
    4. 인터페이스 분리 원칙(ISP , Interface Segregation Principle) - 클래스의 사용자에게 불필요한 인터페이스는 공개하지 말라
    5. 의존 관계 역전 원칙(DIP, Dependency Inversion Principle) - 상위 모듈은 하위 모듈에 의존하지 않는다.
    6. 데메티르 법직 - 직접적인 친구(자기자신, 자신이 가지는 클래스 , 매개변 수로 전달한 클래스)와만 관련한다. 
      • Singleton pattern을 사용하면 이 법칙을 위반한다. => Logger 같은 클래스는 이법칙의 예외일 것 같은데. 이 법칙은 참고로만.


  • 디자인 패턴
    • State pattern과 Strategy pattern은 구현방법이 거의 비슷하지만, 사용하는 상황이 다르므로 구분해서 사용한다. Gog의 디자인 패턴은 구현 방법으로 패펀을 구분해놓은 것이 아니다. 
  • 생성자를 완전한 상태 만들기
    • 호출된 시점에 완전한 상태 , 별도의 초기화 함수를 호출하거나 Setter를 사용해서 설정해야 작동하는 클래스는 주의
    • 어떤 순서로 맴버 함수를 호출해도 문제없이 작동하게 한다. 호출 순서에 제한이 있는 클래슨 사용자에게 부담, 그리고 버그의 원인
  • 멤버 함수 호출 수서와 관련한 대처 방법
    • 상속을 사용한 예 (Template Method pattern)
Class Game {
void run() {
initialize();
while (isRunning()) {
udate();
draw();
}
finalzie();
}

virtual void initialize();
virtual bool isRunning();
virtual void update();
virtual void draw();
virtual void finalize();
};
    • 이양을 사용한 예(Strategy pattern)

Class Game {
virtual void initialize();
virtual bool isRunning();
virtual void update();
virtual void draw();
virtual void finalize();
};

Class GameRunner{

Game* game_;
GameRunner(Game* game) : game_(game) {
}

void run(){
game->initialize();
while(game_->isRunning()){
game_->update();
game_->draw();
}
game_->finalize();
}
}

  • 결합을 생각
    • 결합의 좋고 나쁨은 해당 클래스의 단위 테스트가 얼마나 간단할지 생각해보면 쉽게 판다. 
    • 테스트가 어려운 클래스는 독립성이 낮고, 부적절한 결합 상태일 가능성이 크다. 
    • 부적절한 결합이 발견되었다면 , 추상 인터페이스를 추가함으로써 직접적인 결합 관계를 끊어버린다. 
  • 코드의 수명
    • 재사용할 가치가 있는 부분은 시간을 들여 설계, 코드를 재사용할 수 있게 설계하는 것은 상당한 시간과 노력이 필요. 
    • 항상 비용대비 효율성을 고민
  • 작업의 편의성
    • 코드의 단순함 보다는 작업의 편의성/ 쉽게 공동 작업을 할 수 있는 설계를 하고, 변경 또는 수정할 때 실수가 발생하지 않도록 설계
  • 하나의 방법에 대한 집착
    • 객체 지향을 사용하는 것이 항상 좋은 선택은 아님, 특징에 맞는 프로그래밍 언어와 개발환경을 선택 => 함수형 프로그래밍 등등
    • 여러 언어를 조합하는 경우도 많음 , 목적을 달성하기 위해 가장 효율적인 방버이 무엇일까?를 생각
  • 최소한의 코드만 작성
    • 어떻게 코드를 작성할지가 아니라 => 어떻게 하면 코드를 작성하지 않을까가 중요 / 부수코드를 만들지 말자.. 
  • 원칙과 패턴에 너무 얽매이자 보면 이상한 집착이 생겨서 단순한 코드도 복잡하게 만드는 경향이 있다. 
  • 원칙을 사용한 경유와 사용하지 않을 경우, 클래스를 분할하는 경우와 분할하지 않은 경우 중에 단순한 쪽을 선택
  • 고수일수록 , 좋은 의미의 편법을 잘 활용한다. 쉽게 복잡해지는 부분, 미래에 변경될 수 있는 부분은 시간을 두고 설계하지만 , 변경 가능성이 작은 부분 등은 시간을 들이지 않고 간단하게 끝내버린다.