22. OCP : 개방폐쇄 원칙확장에 대해 열려있고수정에 대해 닫혀있다약속, 표준안을 만드는 것interface, protocol, standard핸드폰 24핀 커넥터HTTP 표준을 rendering 하는 각종 browser 들
25. interface(표준)의 문제점변경 비용이 비싸다interface 가 변경되면 모든 구현 클래스에서 컴파일 에러 발생concrete class 이 뭔지 알기 어렵다BlueRayvs HD-DVD충분히 안정된 후 interface 로미리 바꾸지 않는다첫 번째 총알 맞기게임 하나가 완성된 다음에야?EPIC 의 Unreal Tounament (개밥먹기)
26. SRP(Single Responsibility)단일 책임 원칙OCP(Open Close)개방-폐쇄 원칙LSP(Liskov Substitution)리스코프 교체 원칙ISP(Interface Segregation)인터페이스 격리 원칙DIP(Dependency Inversion)의존 관계 역전 원칙
28. LSP - 리스코프 교체(치환) 원칙기반 클래스(Base Class)의 포인터나 참조값을 사용하는 코드에서는 실제로 어떤 클래스인지 몰라도 쓸 수 있어야 한다하위타입(subtype)은 그것의 기반 타입(base type)에 대해 치환 가능해야 한다is-a 관계를 만족하는가?바바라리스코프(Barbara Liskov). 1988
30. LSP 위반 사례void DrawShape(const Shape& s) { if (typeid(s) == typeid(Square))DrawSquare((Square&)s)); else if (typeid(s) == typeid(Circle))DrawCircle((Circle&)s);}
31. 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); }}
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); }}void Actor::Skill(Actor& target, int s) { if (target.IsPc()) {target.CastPc().SendPacket(“Skilled”, s); } else if (target.IsNpc()) {target.CastNpc().SendEvent(“Skilled”, s); }}Actor 자식 클래스에 Door 가 추가된다면?
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); }
38. 좀 더 실질적인 예제bool Party::CanJoin(Pc& p) { // do something if (IsParty()) { if (GetMember() < 12) { return true; } } else { // 혈맹이라면 if (GetMember() < 140) { // do something
41. LSP(교체가능) 정리concrete 클래스 자체에는 논리적 결함이 없어 보이더라도, 잘못 쓸 가능성이 있다면 문제가 있다수학에서는 (정사각형 is a 직사각형), 하지만 코드에서는 (정사각형 is not a 직사각형) 이 가능하다실보다 득이 많다면, LSP(교체가능)원칙이 깨지더라도 협약(convention)으로 해결할 수도 있다
42. stack(Java 와 C++)java.lang.Objectextended by java.util.AbstractCollectionextended by java.util.AbstractListextended by java.util.Vectorextended by java.util.Stacktemplate<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)의존 관계 역전 원칙
50. 너무 많은 걸 알고 있는 인터페이스class Obj { // 레퍼런스만 관리 virtual intAttack(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)의존 관계 역전 원칙
60. SRP(Single Responsibility) 단일 책임클래스가 변경되는 이유는 유일해야 한다OCP(Open Close) 개방폐쇄 원칙확장에 대해 열려있고수정에 대해 닫혀있다LSP(Liskov Substitution) 리스코프 교체Base Class의 포인터나 참조값을 사용하는 코드에서는 실제로 어떤 클래스인지 몰라도 쓸 수 있어야 한다ISP(Interface Segregation) 인터페이스 격리클라이언트는 자신이 쓰지않는 인터페이스에 의존하지 않는다DIP(Dependency Inversion) 의존 관계 역전상위 모듈이 하위 모듈에게 의존하면 안 된다
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(인터페이스분리)클라이언트가 클래스의 특정 기능만 이용한다면 그런 기능의 부분 집합을 별도 인터페이스로 추출
65. 현실은 시궁창// 에라 모르겠다// 해볼 수도 있겠으나 귀찮다. 일단 여기까지// 구현의 편의를 위해 이렇게 한다. 시간이 없거든// 작업중입니다T_T// 그래 나도 이러면 안되는 지 알어... 미안해...// 원래는 lock 걸어야 하지만 이 정도면 괜찮을 듯? 한 번이라도 죽으면 lock 걸자.07.10.xx// 죽었다. lock 쓰는 걸로 바꾼다. 07.12.xx// 사실 이렇게 짜면 안 되는데 이 클래스는 너무 고치기 무서워서 못 건드리겠음// 다시는 이런 일이 없어야 할 것임
71. Reference실전 코드로 배우는 실용주의 디자인 패턴소프트웨어 개발의 지혜 - 야스미디어zdnet - 객체지향 SW 설계의 원칙http://www.zdnet.co.kr/ArticleView.asp?artice_id=00000039134727http://www.zdnet.co.kr/ArticleView.asp?artice_id=00000039135552http://www.zdnet.co.kr/ArticleView.asp?artice_id=00000039139151http://www.zdnet.co.kr/ArticleView.asp?artice_id=00000039137043http://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_rightThat’s not my jobhttp://life-engineering.com/2008/04/28/thats-not-my-job/자동차 사고https://www.youngsamsung.com/pblog.do?cmd=view&seq=459&memId=4&categoryId=49내가 짰구나http://www.slideshare.net/wgshim/experience-report-agile-adoption-stories-in-lg-electronics