OOP 설계 원칙
S.O.L.I.D.
                       v.2.5
                 NCsoft 박일
   http://parkpd.egloos.com
OOP 설계 원칙
S.O.L.I.D.  이러다가 v.10.0 까지 나올 기세
                       v.2.5
                 NCsoft 박일
   http://parkpd.egloos.com
강사 소개




KGC   07 게임에 적용해 보는 TDD
KGC   08, NCDC 09 Lineage2 Production System
KGC   09, NDC 10 사례로 살펴보는 디버깅
KGC   10 낡은 코드에 테스트 코드 넣기
잠깐만 UML 을 배웁시다
잠깐만 UML 을 배웁시다
잠깐만 UML 을 배웁시다
잠깐만 UML 을 배웁시다
대원칙 - 높은 응집도, 낮은 결합도
• 응집도 : 하나의 클래스가 하나의 기능
  (책임)을 온전히 순도 높게 담당하는 정도
• 결합도 : 클래스간의 서로 다른 책임들이 얽혀
  있어서 상호의존도가 높은 정도
SRP(Single Responsibility)
  단일 책임 원칙
OCP(Open Close)
  개방-폐쇄 원칙
LSP(Liskov Substitution)
  리스코프 교체 원칙
ISP(Interface Segregation)
  인터페이스 격리 원칙
DIP(Dependency Inversion)
  의존 관계 역전 원칙
SRP(Single Responsibility)
 단일 책임 원칙
OCP(Open Close)
  개방-폐쇄 원칙
LSP(Liskov Substitution)
  리스코프 교체 원칙
ISP(Interface Segregation)
  인터페이스 격리 원칙
DIP(Dependency Inversion)
  의존 관계 역전 원칙
SRP (Single Responsibility)
            단일 책임 원칙
SRP : 단일 책임 원칙
한 클래스는 하나의 역할만 맡는다
클래스가 변경되는 이유는 유일해야 한다
무엇이 좋아졌는가?
• 코드 변경의 영향이 미치는 범위 최소화
• 코드 응집성 향상
• 단위테스트에 유리
 – InterestRate, ExchangeRate 객체는 Account 의
   private 변수로, 각 클래스의 메서드는 public 으로
 – 캡슐화와 테스트 용의성 둘 다 만족
SRP != (크기가 작은 클래스)
• 클래스의 크기는 작을수록 좋지만 여러 클래
  스끼리의 교통정리를 해 주는 클래스도 필요
• 관련 클래스를 묶어 데이터 연관성
• 각 part 를 연결하는 whole 의 역할
• player -> ((inventory -> item), skill)
SRP(Single Responsibility)
  단일 책임 원칙

OCP(Open Close)
 개방-폐쇄 원칙
LSP(Liskov Substitution)
  리스코프 교체 원칙
ISP(Interface Segregation)
  인터페이스 격리 원칙
DIP(Dependency Inversion)
  의존 관계 역전 원칙
OCP(Open Close)
   개방폐쇄 원칙
표준이 없는 세상
표준이 없는 세상
표준이 없는 세상
OCP : 개방폐쇄 원칙
확장에 대해 열려있고 수정에 대해 닫혀있다
약속, 표준안을 만드는 것
 interface, protocol, standard
 핸드폰 24핀 커넥터
 HTTP 표준을 rendering 하는 각종 browser 들
interface(표준)의 문제점
• 변경 비용이 비싸다
 – interface 가 변경되면 모든 구현 클
   래스에서 컴파일 에러 발생
 – concrete class 이 뭔지 알기 어렵다
 – BlueRay vs HD-DVD
• 충분히 안정된 후 interface 로
 – 미리 바꾸지 않는다
 – 첫 번째 총알 맞기
 – 게임 하나가 완성된 다음에야?
   • EPIC 의 Unreal Tounament (개밥먹기)
SRP(Single Responsibility)
  단일 책임 원칙
OCP(Open Close)
  개방-폐쇄 원칙

LSP(Liskov Substitution)
 리스코프 교체 원칙
ISP(Interface Segregation)
   인터페이스 격리 원칙
DIP(Dependency Inversion)
   의존 관계 역전 원칙
LSP(Liskov Substitution)
리스코프 교체(치환) 원칙
LSP - 리스코프 교체(치환) 원칙
• 기반 클래스(Base Class)의 포인터나 참
  조값을 사용하는 코드에서는 실제로 어떤
  클래스인지 몰라도 쓸 수 있어야 한다
• 하위타입(subtype)은 그것의 기반 타입
  (base type)에 대해 치환 가능해야 한다
• is-a 관계를 만족하는가?
• 바바라 리스코프(Barbara Liskov). 1988
‘하위 호환성’ - DirectX
dll 이 바뀌어도 문제가 없다
LSP 위반 사례
void DrawShape(const Shape& s) {
  if (typeid(s) == typeid(Square))
      DrawSquare((Square&)s));
  else if (typeid(s) == typeid(Circle))
      DrawCircle((Circle&)s);
}
LSP(교체가능) 위반 사례
void Actor::Attack(Actor& target, int damage) {
   if (target.IsPc()) {
         target.CastPc().SendPacket(“Attacked”, damage);
   } else if (target.IsNpc()) {
         target.CastNpc().SendEvent(“Attacked”, damage);
   }
}
void Actor::Skill(Actor& target, int s) {
   if (target.IsPc()) {
         target.CastPc().SendPacket(“Skilled”, s);
   } else if (target.IsNpc()) {
         target.CastNpc().SendEvent(“Skilled”, s);
   }
}
LSP(교체가능) 위반 사례
          OCP(개방폐쇄)도 위반!
void Actor::Attack(Actor& target, int damage) {
   if (target.IsPc()) {
         target.CastPc().SendPacket(“Attacked”, damage);
   } else if (target.IsNpc()) {
         target.CastNpc().SendEvent(“Attacked”, damage);
   }
}
  Actor 자식 클래스에
void Actor::Skill(Actor& target, int s) {
   if (target.IsPc()) {
         target.CastPc().SendPacket(“Skilled”, s);
  Door 가 추가된다면?
   } else if (target.IsNpc()) {
         target.CastNpc().SendEvent(“Skilled”, s);
   }
}
LSP(교체가능) 만족
void Actor::Attack(Actor& target, int damage) {
   target.Event(“Attacked”, damage);
}
void Actor::Skill(Actor& target, int s) {
   target.Event(“Skilled”, s);
}
virtual void Actor::Event(string& type, int n) = 0;
void Pc::Event(string& type, int n) { SendPacket(type, n); }
void Npc::Event(string& type, int n) { SendEvent(type, n); }
void Door::Event(string& type, int n) { DoorEvent(type, n); }
직사각형을 상속받은 정사각형
직사각형을 상속받은 정사각형
LSP(교체가능)를 만족시키려면
좀 더 실질적인 예제
좀 더 실질적인 예제
bool Party::CanJoin(Pc& p) {
     // do something
     if (IsParty()) {
            if (GetMember() < 12) {
                  return true;
            }
     } else {     // 혈맹이라면
            if (GetMember() < 140) {
     // do something
좀 더 실질적인 예제
왜 이런 일이?
That’s not my job
LSP(교체가능) 정리
• concrete 클래스 자체에는 논리적 결함이
  없어 보이더라도, 잘못 쓸 가능성이 있다
  면 문제가 있다
 – 수학에서는 (정사각형 is a 직사각형), 하지만
   코드에서는 (정사각형 is not a 직사각형) 이
   가능하다
 – 실보다 득이 많다면, LSP(교체가능)원칙이 깨
   지더라도 협약(convention)으로 해결할 수도
   있다
stack(Java 와 C++)
java.lang.Object
    extended by java.util.AbstractCollection
        extended by java.util.AbstractList
            extended by java.util.Vector
                extended by java.util.Stack



template<class _Ty, class _Container = deque<_Ty> >
class stack {
void push(const value_type& _Val) { c.push_back(_Val); }
void pop() { c.pop_back(); }
_Container c;
};
SRP(Single Responsibility)
  단일 책임 원칙
OCP(Open Close)
  개방-폐쇄 원칙
LSP(Liskov Substitution)
  리스코프 교체 원칙

ISP(Interface Segregation)
  인터페이스 격리 원칙
DIP(Dependency Inversion)
  의존 관계 역전 원칙
ISP(Interface Segregation)
      인터페이스 격리 원칙
ISP - 인터페이스 격리 원칙
ISP - 인터페이스 격리 원칙
너무 많은 걸 알고 있는 인터페이스
class Obj { // 레퍼런스만 관리
            Attack
  virtual int         (Obj& o) {
       ASSERT(0); // Actor 에서만 호출해야 함
       return 0;
  }
};
class Actor : public Obj {
   virtual int Attack(Obj& o) { … }
};
std::map<int, Obj*> g_ObjDB;
g_ObjDB[1]->Attack(t);
필요한 것만 알고 있는 인터페이스
class Obj {     // 레퍼런스만 관리
};
class Actor : public Obj {
   int Attack(Actor& o) { … }
};
std::map<int, Obj*> g_ObjDB;
std::map<int, Actor*> g_ActorDB;
g_ActorDB[1]->Attack(t);
ISP(인터페이스분리) 정리
• 같은 로직이 반복되면 up-class 하고 싶겠
  지만 욕심내지 않는다
 – 코드 재사용은 상속 대신 포함(aggregation)으로
   • CTimerObject 대신
     ITimerObject 와 CTimerHandler 활용
 – 상속은 코드 재사용보다는 OCP(개방폐쇄)나
   LSP(교체가능), DIP(의존역전)를 위해 사용
SRP(Single Responsibility)
   단일 책임 원칙
OCP(Open Close)
   개방-폐쇄 원칙
LSP(Liskov Substitution)
   리스코프 교체 원칙
ISP(Interface Segregation)
   인터페이스 격리 원칙

DIP(Dependency Inversion)
 의존 관계 역전 원칙
DIP(Dependency Inversion)
       의존 관계 역전 원칙
DIP - 의존 관계 역전 원칙
• 상위 수준 모듈이 하위 수준 모듈에 의존하면 안 된다
• 추상(Abstraction) 에서 상세(Detail) 구현에 의존하면
  안 된다
왜 의존 관계 역전인가?




Button 은 Lamp 에
의존관계다
DIP - 의존 관계 역전 원칙
• 게임 엔진의 문제
 – 개발 도중, 엔진이 버전업 되었다면?
• interface 를 누가 결정하고 관리하는가?
 – OS 업체?
 – Printer 같은 주변기기 업체?
정리해 봅시다
• SRP(Single Responsibility) 단일 책임
  – 클래스가 변경되는 이유는 유일해야 한다
• OCP(Open Close) 개방폐쇄 원칙
  – 확장에 대해 열려있고 수정에 대해 닫혀있다
• LSP(Liskov Substitution) 리스코프 교체
  – Base Class의 포인터나 참조값을 사용하는 코드
    에서는 실제로 어떤 클래스인지 몰라도 쓸 수 있
    어야 한다
• ISP(Interface Segregation) 인터페이스 격리
  – 클라이언트는 자신이 쓰지 않는 인터페이스에 의
    존하지 않는다
• DIP(Dependency Inversion) 의존 관계 역전
  – 상위 모듈이 하위 모듈에게 의존하면 안 된다
비교해 봅시다
• OCP(개방폐쇄)
 – 인터페이스가 같은지?
 – DrawShape를 호출하는 프로그래머 입장
• LSP(교체가능)
 – 기반 클래스(Base Class)의 포인터나 참조값
   을 사용하는 코드에서는 실제로 어떤 클래스
   인지 몰라도 쓸 수 있어야 한다(정보은닉)
 – DrawShape를 구현하는 프로그래머 입장
   void DrawShape(const Shape& s) {
         if (typeid(s) == typeid(Square))
                 DrawSquare((Square&)s));
         else if (typeid(s) == typeid(Circle))
                 DrawCircle((Circle&)s);
   }
• SRP(단일책임)
 – 여러 책임이 섞여 있는 클래스를 책임별 분리
• ISP(인터페이스분리)
 – 클라이언트가 클래스의 특정 기능만 이용한다
   면 그런 기능의 부분 집합을 별도 인터페이스
   로 추출
• OCP(개방폐쇄)
 – 코드 추가만으로 기능 변경 가능한가
• DIP(의존역전)
 – 변경의 주체가 누구인가
현실은 시궁창
// 에라 모르겠다
// 해볼 수도 있겠으나 귀찮다. 일단 여기까지
// 구현의 편의를 위해 이렇게 한다. 시간이 없거든
// 작업중입니다 T_T
// 그래 나도 이러면 안되는 지 알어... 미안해...
// 원래는 lock 걸어야 하지만 이 정도면 괜찮을 듯?
   한 번이라도 죽으면 lock 걸자. 07.10.xx
// 죽었다. lock 쓰는 걸로 바꾼다. 07.12.xx
// 사실 이렇게 짜면 안 되는데 이 클래스는 너무 고
   치기 무서워서 못 건드리겠음
// 다시는 이런 일이 없어야 할 것임
현실은 시궁창
당장 업데이트 해야 하는데 5대 법칙이 어쩌고 하면 혼날지도
그럼에도 불구하고
설계를 신경써야 한다
결론
클래스를 만들때는 고객의 입장에서 생각할 것
 놀래키지 않는다
구조를 잡을때는 신중하게
실제로 써 본 뒤에 구조 잡기
안정화 단계란 영원히 오지 않을지도?
 안정된 코드는 오래된 코드
 언제가 “적당”한가?
라이브러리보다는 비즈니스 layer 가 중요
절대적인 법칙은 없다
Q&A
Reference
• 실전 코드로 배우는 실용주의 디자인 패턴
• 소프트웨어 개발의 지혜 - 야스미디어
• zdnet - 객체지향 SW 설계의 원칙
   – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391
     34727
   – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391
     35552
   – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391
     39151
   – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391
     37043
• http://www.objectmentor.com/resources/publishedArticles
  .html
• 실용주의 디자인 패턴 0장
• 애자일 프로그래밍 - 남기룡
사진
•   높은 응집도, 낮은 결합도
     – http://improf.egloos.com/2309582
     – 실용주의 디자인 패턴
•   이미지 출처
     – http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/solid-
       development-principles-in-motivational-pictures.aspx
•   개발자 좀 살려주세요
     – http://resistan.com/savethedeveloper/
•   사각형 집합
     – http://middle.edupia.com/SchoolBook/seb/jd_seb1_content.asp?nTerm=2&nYear
       =8&nConID=669&nCatID=250&nDaeNumber=5&target=jd_seb_right
•   That’s not my job
     – http://life-engineering.com/2008/04/28/thats-not-my-job/
•   자동차 사고
     – https://www.youngsamsung.com/pblog.do?cmd=view&seq=459&memId=4&cate
       goryId=49
•   내가 짰구나
     – http://www.slideshare.net/wgshim/experience-report-agile-adoption-stories-
       in-lg-electronics

Oop design principle SOLID

  • 1.
    OOP 설계 원칙 S.O.L.I.D. v.2.5 NCsoft 박일 http://parkpd.egloos.com
  • 2.
    OOP 설계 원칙 S.O.L.I.D. 이러다가 v.10.0 까지 나올 기세 v.2.5 NCsoft 박일 http://parkpd.egloos.com
  • 3.
    강사 소개 KGC 07 게임에 적용해 보는 TDD KGC 08, NCDC 09 Lineage2 Production System KGC 09, NDC 10 사례로 살펴보는 디버깅 KGC 10 낡은 코드에 테스트 코드 넣기
  • 4.
    잠깐만 UML 을배웁시다
  • 5.
    잠깐만 UML 을배웁시다
  • 6.
    잠깐만 UML 을배웁시다
  • 7.
    잠깐만 UML 을배웁시다
  • 8.
    대원칙 - 높은응집도, 낮은 결합도 • 응집도 : 하나의 클래스가 하나의 기능 (책임)을 온전히 순도 높게 담당하는 정도 • 결합도 : 클래스간의 서로 다른 책임들이 얽혀 있어서 상호의존도가 높은 정도
  • 9.
    SRP(Single Responsibility) 단일 책임 원칙 OCP(Open Close) 개방-폐쇄 원칙 LSP(Liskov Substitution) 리스코프 교체 원칙 ISP(Interface Segregation) 인터페이스 격리 원칙 DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 10.
    SRP(Single Responsibility) 단일책임 원칙 OCP(Open Close) 개방-폐쇄 원칙 LSP(Liskov Substitution) 리스코프 교체 원칙 ISP(Interface Segregation) 인터페이스 격리 원칙 DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 11.
    SRP (Single Responsibility) 단일 책임 원칙
  • 12.
    SRP : 단일책임 원칙 한 클래스는 하나의 역할만 맡는다 클래스가 변경되는 이유는 유일해야 한다
  • 15.
    무엇이 좋아졌는가? • 코드변경의 영향이 미치는 범위 최소화 • 코드 응집성 향상 • 단위테스트에 유리 – InterestRate, ExchangeRate 객체는 Account 의 private 변수로, 각 클래스의 메서드는 public 으로 – 캡슐화와 테스트 용의성 둘 다 만족
  • 16.
    SRP != (크기가작은 클래스) • 클래스의 크기는 작을수록 좋지만 여러 클래 스끼리의 교통정리를 해 주는 클래스도 필요 • 관련 클래스를 묶어 데이터 연관성 • 각 part 를 연결하는 whole 의 역할 • player -> ((inventory -> item), skill)
  • 17.
    SRP(Single Responsibility) 단일 책임 원칙 OCP(Open Close) 개방-폐쇄 원칙 LSP(Liskov Substitution) 리스코프 교체 원칙 ISP(Interface Segregation) 인터페이스 격리 원칙 DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 18.
    OCP(Open Close) 개방폐쇄 원칙
  • 19.
  • 20.
  • 21.
  • 22.
    OCP : 개방폐쇄원칙 확장에 대해 열려있고 수정에 대해 닫혀있다 약속, 표준안을 만드는 것 interface, protocol, standard 핸드폰 24핀 커넥터 HTTP 표준을 rendering 하는 각종 browser 들
  • 25.
    interface(표준)의 문제점 • 변경비용이 비싸다 – interface 가 변경되면 모든 구현 클 래스에서 컴파일 에러 발생 – concrete class 이 뭔지 알기 어렵다 – BlueRay vs HD-DVD • 충분히 안정된 후 interface 로 – 미리 바꾸지 않는다 – 첫 번째 총알 맞기 – 게임 하나가 완성된 다음에야? • EPIC 의 Unreal Tounament (개밥먹기)
  • 26.
    SRP(Single Responsibility) 단일 책임 원칙 OCP(Open Close) 개방-폐쇄 원칙 LSP(Liskov Substitution) 리스코프 교체 원칙 ISP(Interface Segregation) 인터페이스 격리 원칙 DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 27.
  • 28.
    LSP - 리스코프교체(치환) 원칙 • 기반 클래스(Base Class)의 포인터나 참 조값을 사용하는 코드에서는 실제로 어떤 클래스인지 몰라도 쓸 수 있어야 한다 • 하위타입(subtype)은 그것의 기반 타입 (base type)에 대해 치환 가능해야 한다 • is-a 관계를 만족하는가? • 바바라 리스코프(Barbara Liskov). 1988
  • 29.
    ‘하위 호환성’ -DirectX dll 이 바뀌어도 문제가 없다
  • 30.
    LSP 위반 사례 voidDrawShape(const Shape& s) { if (typeid(s) == typeid(Square)) DrawSquare((Square&)s)); else if (typeid(s) == typeid(Circle)) DrawCircle((Circle&)s); }
  • 31.
    LSP(교체가능) 위반 사례 voidActor::Attack(Actor& target, int damage) { if (target.IsPc()) { target.CastPc().SendPacket(“Attacked”, damage); } else if (target.IsNpc()) { target.CastNpc().SendEvent(“Attacked”, damage); } } void Actor::Skill(Actor& target, int s) { if (target.IsPc()) { target.CastPc().SendPacket(“Skilled”, s); } else if (target.IsNpc()) { target.CastNpc().SendEvent(“Skilled”, s); } }
  • 32.
    LSP(교체가능) 위반 사례 OCP(개방폐쇄)도 위반! void Actor::Attack(Actor& target, int damage) { if (target.IsPc()) { target.CastPc().SendPacket(“Attacked”, damage); } else if (target.IsNpc()) { target.CastNpc().SendEvent(“Attacked”, damage); } } Actor 자식 클래스에 void Actor::Skill(Actor& target, int s) { if (target.IsPc()) { target.CastPc().SendPacket(“Skilled”, s); Door 가 추가된다면? } else if (target.IsNpc()) { target.CastNpc().SendEvent(“Skilled”, s); } }
  • 33.
    LSP(교체가능) 만족 void Actor::Attack(Actor&target, int damage) { target.Event(“Attacked”, damage); } void Actor::Skill(Actor& target, int s) { target.Event(“Skilled”, s); } virtual void Actor::Event(string& type, int n) = 0; void Pc::Event(string& type, int n) { SendPacket(type, n); } void Npc::Event(string& type, int n) { SendEvent(type, n); } void Door::Event(string& type, int n) { DoorEvent(type, n); }
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
    좀 더 실질적인예제 bool Party::CanJoin(Pc& p) { // do something if (IsParty()) { if (GetMember() < 12) { return true; } } else { // 혈맹이라면 if (GetMember() < 140) { // do something
  • 39.
  • 40.
  • 41.
    LSP(교체가능) 정리 • concrete클래스 자체에는 논리적 결함이 없어 보이더라도, 잘못 쓸 가능성이 있다 면 문제가 있다 – 수학에서는 (정사각형 is a 직사각형), 하지만 코드에서는 (정사각형 is not a 직사각형) 이 가능하다 – 실보다 득이 많다면, LSP(교체가능)원칙이 깨 지더라도 협약(convention)으로 해결할 수도 있다
  • 42.
    stack(Java 와 C++) java.lang.Object extended by java.util.AbstractCollection extended by java.util.AbstractList extended by java.util.Vector extended by java.util.Stack template<class _Ty, class _Container = deque<_Ty> > class stack { void push(const value_type& _Val) { c.push_back(_Val); } void pop() { c.pop_back(); } _Container c; };
  • 43.
    SRP(Single Responsibility) 단일 책임 원칙 OCP(Open Close) 개방-폐쇄 원칙 LSP(Liskov Substitution) 리스코프 교체 원칙 ISP(Interface Segregation) 인터페이스 격리 원칙 DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 44.
    ISP(Interface Segregation) 인터페이스 격리 원칙
  • 45.
    ISP - 인터페이스격리 원칙
  • 49.
    ISP - 인터페이스격리 원칙
  • 50.
    너무 많은 걸알고 있는 인터페이스 class Obj { // 레퍼런스만 관리 Attack virtual int (Obj& o) { ASSERT(0); // Actor 에서만 호출해야 함 return 0; } }; class Actor : public Obj { virtual int Attack(Obj& o) { … } }; std::map<int, Obj*> g_ObjDB; g_ObjDB[1]->Attack(t);
  • 51.
    필요한 것만 알고있는 인터페이스 class Obj { // 레퍼런스만 관리 }; class Actor : public Obj { int Attack(Actor& o) { … } }; std::map<int, Obj*> g_ObjDB; std::map<int, Actor*> g_ActorDB; g_ActorDB[1]->Attack(t);
  • 52.
    ISP(인터페이스분리) 정리 • 같은로직이 반복되면 up-class 하고 싶겠 지만 욕심내지 않는다 – 코드 재사용은 상속 대신 포함(aggregation)으로 • CTimerObject 대신 ITimerObject 와 CTimerHandler 활용 – 상속은 코드 재사용보다는 OCP(개방폐쇄)나 LSP(교체가능), DIP(의존역전)를 위해 사용
  • 53.
    SRP(Single Responsibility) 단일 책임 원칙 OCP(Open Close) 개방-폐쇄 원칙 LSP(Liskov Substitution) 리스코프 교체 원칙 ISP(Interface Segregation) 인터페이스 격리 원칙 DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 54.
    DIP(Dependency Inversion) 의존 관계 역전 원칙
  • 55.
    DIP - 의존관계 역전 원칙 • 상위 수준 모듈이 하위 수준 모듈에 의존하면 안 된다 • 추상(Abstraction) 에서 상세(Detail) 구현에 의존하면 안 된다
  • 56.
    왜 의존 관계역전인가? Button 은 Lamp 에 의존관계다
  • 57.
    DIP - 의존관계 역전 원칙 • 게임 엔진의 문제 – 개발 도중, 엔진이 버전업 되었다면? • interface 를 누가 결정하고 관리하는가? – OS 업체? – Printer 같은 주변기기 업체?
  • 58.
  • 60.
    • SRP(Single Responsibility)단일 책임 – 클래스가 변경되는 이유는 유일해야 한다 • OCP(Open Close) 개방폐쇄 원칙 – 확장에 대해 열려있고 수정에 대해 닫혀있다 • LSP(Liskov Substitution) 리스코프 교체 – Base Class의 포인터나 참조값을 사용하는 코드 에서는 실제로 어떤 클래스인지 몰라도 쓸 수 있 어야 한다 • ISP(Interface Segregation) 인터페이스 격리 – 클라이언트는 자신이 쓰지 않는 인터페이스에 의 존하지 않는다 • DIP(Dependency Inversion) 의존 관계 역전 – 상위 모듈이 하위 모듈에게 의존하면 안 된다
  • 61.
  • 62.
    • OCP(개방폐쇄) –인터페이스가 같은지? – DrawShape를 호출하는 프로그래머 입장 • LSP(교체가능) – 기반 클래스(Base Class)의 포인터나 참조값 을 사용하는 코드에서는 실제로 어떤 클래스 인지 몰라도 쓸 수 있어야 한다(정보은닉) – DrawShape를 구현하는 프로그래머 입장 void DrawShape(const Shape& s) { if (typeid(s) == typeid(Square)) DrawSquare((Square&)s)); else if (typeid(s) == typeid(Circle)) DrawCircle((Circle&)s); }
  • 63.
    • SRP(단일책임) –여러 책임이 섞여 있는 클래스를 책임별 분리 • ISP(인터페이스분리) – 클라이언트가 클래스의 특정 기능만 이용한다 면 그런 기능의 부분 집합을 별도 인터페이스 로 추출
  • 64.
    • OCP(개방폐쇄) –코드 추가만으로 기능 변경 가능한가 • DIP(의존역전) – 변경의 주체가 누구인가
  • 65.
    현실은 시궁창 // 에라모르겠다 // 해볼 수도 있겠으나 귀찮다. 일단 여기까지 // 구현의 편의를 위해 이렇게 한다. 시간이 없거든 // 작업중입니다 T_T // 그래 나도 이러면 안되는 지 알어... 미안해... // 원래는 lock 걸어야 하지만 이 정도면 괜찮을 듯? 한 번이라도 죽으면 lock 걸자. 07.10.xx // 죽었다. lock 쓰는 걸로 바꾼다. 07.12.xx // 사실 이렇게 짜면 안 되는데 이 클래스는 너무 고 치기 무서워서 못 건드리겠음 // 다시는 이런 일이 없어야 할 것임
  • 66.
    현실은 시궁창 당장 업데이트해야 하는데 5대 법칙이 어쩌고 하면 혼날지도
  • 67.
  • 68.
  • 69.
    결론 클래스를 만들때는 고객의입장에서 생각할 것 놀래키지 않는다 구조를 잡을때는 신중하게 실제로 써 본 뒤에 구조 잡기 안정화 단계란 영원히 오지 않을지도? 안정된 코드는 오래된 코드 언제가 “적당”한가? 라이브러리보다는 비즈니스 layer 가 중요 절대적인 법칙은 없다
  • 70.
  • 71.
    Reference • 실전 코드로배우는 실용주의 디자인 패턴 • 소프트웨어 개발의 지혜 - 야스미디어 • zdnet - 객체지향 SW 설계의 원칙 – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391 34727 – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391 35552 – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391 39151 – http://www.zdnet.co.kr/ArticleView.asp?artice_id=000000391 37043 • http://www.objectmentor.com/resources/publishedArticles .html • 실용주의 디자인 패턴 0장 • 애자일 프로그래밍 - 남기룡
  • 72.
    사진 • 높은 응집도, 낮은 결합도 – http://improf.egloos.com/2309582 – 실용주의 디자인 패턴 • 이미지 출처 – http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/solid- development-principles-in-motivational-pictures.aspx • 개발자 좀 살려주세요 – http://resistan.com/savethedeveloper/ • 사각형 집합 – http://middle.edupia.com/SchoolBook/seb/jd_seb1_content.asp?nTerm=2&nYear =8&nConID=669&nCatID=250&nDaeNumber=5&target=jd_seb_right • That’s not my job – http://life-engineering.com/2008/04/28/thats-not-my-job/ • 자동차 사고 – https://www.youngsamsung.com/pblog.do?cmd=view&seq=459&memId=4&cate goryId=49 • 내가 짰구나 – http://www.slideshare.net/wgshim/experience-report-agile-adoption-stories- in-lg-electronics