Object-Oriented Design Agile for Software Development Story 7. 작 성 자 : 고형호 메 일 : hyungho.ko@gmail.com 홈페이지 : 최초작성일 : 2007.08.10 최종작성일 : 2007.09.05 1
Goal A Set of Contained Responsibilities 2
Content 1. Customer Requirement 2. Customer Requirement Analysis 3. Structure Improvement 4. SRP(Single Responsibility Principle) Violation 5. Design Pattern 6. Class Diagram in Practice 7. Design Pattern in Practice 8. Summary 3
4 1. Customer Requirement
Customer Requirement 요구사항 : Rectangle, Ellipse 도형을그린다. ( 외부와의계약, 변화하지않는것 ) 철저히은닉되어야한다. 5
Customer Requirement 요구사항 : 그리기 : Rectangle, Ellipse 도형 OOD 원칙구현 SRP Client DIP <<interface>> IShape 그리기 ( 외부와의계약, 변화하지않는것 ) RectangleShape OCP(LSP) EllipseShape Rectangle, Ellipse 6
Customer Requirement 요구사항 : Rectangle, Ellipse 이합성 ( 合成 ) 된도형을그린다. Rectangle ( 외부와의계약, 변화하지않는것 ) Ellipse Rectangle, Ellipse 합성 ( 合成 ) 된도형 합성 ( 合成 ) : 둘이상의것을합쳐서하나를이룸. 철저히은닉되어야한다. 7
Customer Requirement 요구사항 : 그리기 : Rectangle, Ellipse, 합성 ( 合成 ) 된도형 OOD 원칙구현 SRP Client DIP <<interface>> IShape 그리기 ( 외부와의계약, 변화하지않는것 ) RectangleShape Rectangle EllipseShape Ellipse OCP(LSP) CompositeShape 합성된도형 8
9 2. Customer Requirement Analysis
Customer Requirement Analysis 요구사항 : Rectangle, Ellipse 이합성 ( 合成 ) 된도형을그린다. 합성 ( 合成 ) 된도형은 Rectangle, Ellipse 도형을그리기위한추가책임이다. Sub- 요구사항정리 요구사항 : Rectangle, Ellipse 이합성 ( 合成 ) 된도형을그린다. Sub- 10
Customer Requirement Analysis /Sub- 관계 Sub- 는 의합성 ( 合成 ) 으로이루어진다. 합성 ( 合成 ) : 둘이상의것을합쳐서하나를이룸. 합성된도형 Sub- Rectangle Ellipse 1 개 ( 전체 ) N 개 ( 부분 ) /Sub- 관계정리 Sub- = : : N ( 부분 ) 1 ( 전체 ) 11
Customer Requirement Analysis 요구사항 : Rectangle, Ellipse 이합성 ( 合成 ) 된도형을그린다. Sub- Sub- 는 의추가책임이므로, 의구현은 에게위임한다. Ex. 그리기 합성된도형 Sub- Rectangle Ellipse 12 요구사항정리 요구사항 : Rectangle, Ellipse 이합성 ( 合成 ) 된도형을그린다. Sub-
Customer Requirement Analysis : 그리기 요구사항 : Rectangle, Ellipse Sub- : 합성 ( 合成 ) 된도형 ( : Sub- = N : 1) Decorator Pattern 구현 그리기 ( 외부와의계약, 변화하지않는것 ) <<interface>> IShape RectangleShape Rectangle EllipseShape Ellipse DecoratorShape #DecoratorShape(IShape*) CompositeShape 책임구분 (/Sub- 구분 ) 합성된도형 Sub- 1 개 ( 전체 ) 13 N 개 ( 부분 )
Customer Requirement Analysis : Sub- = N : ( 부분 ) 1 ( 전체 ) 전체는부분을관리하기위한추가작업이필요하다. 관리구현 그리기 ( 외부와의계약, 변화하지않는것 ) <<interface>> IShape 14 RectangleShape Rectangle N 개 ( 부분 ) EllipseShape Ellipse DecoratorShape #DecoratorShape(IShape*) CompositeShape +Add(IShape*) +Remove(IShape*) 책임구분 (/Sub- 구분 ) 합성된도형 Sub- 1 개 ( 전체 )
15 3. Structure Improvement
Structure Improvement 구조단순화 그리기 ( 외부와의계약, 변화하지않는것 ) <<interface>> IShape RectangleShape EllipseShape DecoratorShape #DecoratorShape(IShape*) 책임구분 (/Sub- 구분 ) 16 Rectangle N 개 ( 부분 ) DecoratorShape 역할 Ellipse CompositeShape +Add(IShape*) +Remove(IShape*) Sub- 추가로인한중복코드및클래스구조복잡성을제거한다. 즉, 전제조건은 : Sub- = 1 : N 이다. 그러나, : Sub- = N : 1 관계에서는그역할이약하다. 합성된도형 Sub- 1 개 ( 전체 )
Structure Improvement : Sub- = N : 1 관계에서는그 Decorator 클래스역할이약하다. (/Sub- 구분 ) /Sub- 구분제거 그리기 ( 외부와의계약, 변화하지않는것 ) <<interface>> IShape RectangleShape EllipseShape CompositeShape Rectangle Ellipse +Add(IShape*) +Remove(IShape*) 합성된도형 Sub- N 개 ( 부분 ) 1 개 ( 전체 ) 17
Structure Improvement 세부구현 <<interface>> IShape RectangleShape EllipseShape CompositeShape +Add(IShape*) +Remove(IShape*) 18 누락된요구사항 : 도형 () 관리하기 }; class CompositeShape : public IShape private: list<ishape*> m_plist; public: void Add(IShape* pshape) // m_plist 에 pshape 추가 } void Remove(IShape* pshape) // m_plist 에서 pshape 제거 } void Draw(const Graphics& g) list<ishape*>::iterator it = m_plist.begin(); while(it!= m_plist.end()) // } }
Structure Improvement <<interface>> IShape RectangleShape EllipseShape CompositeShape +Add(IShape*) +Remove(IShape*) 19 누락된요구사항 : 도형 () 관리하기 요구사항 : 그리기 class CompositeShape : public IShape private: list<ishape*> m_plist; public: void Add(IShape* pshape) void Remove(IShape* pshape) void Draw(const Graphics& g) }; 요구사항재정의 : Rectangle, Ellipse Sub- : 합성 ( 合成 ) 된도형 : 도형 () 관리 : 합성 ( 合成 ) 된도형
요구사항 : 그리기 : Rectangle, Ellipse Sub- : 합성 ( 合成 ) 된도형 : 도형 () 관리 : 합성 ( 合成 ) 된도형 OOD 원칙구현 도형 () 관리 ( 외부와의계약, 변화하지않는것 ) 20 Client RectangleShape DIP OCP(LSP) Rectangle 그리기 ( 외부와의계약, 변화하지않는것 ) <<interface>> IShape EllipseShape Ellipse SRP SRP <<interface>> IComposite +Add(IShape*) +Remove(IShape*) CompositeShape OCP(LSP) +Add(IShape*) +Remove(IShape*) 합성된도형 Sub- 합성된도형 DIP AnotherClient
Structure Improvement SRP <<interface>> IComposite <<interface>> IShape SRP +Add(IShape*) +Remove(IShape*) AnotherClient Client RectangleShape EllipseShape CompositeShape +Add(IShape*) +Remove(IShape*) - 문제점 : Client 가합성 ( 合成 ) 된도형을구성하기위해 IComposite 에직접접근할수없다. - 원인 : 인터페이스가분리되어있어클라이언트 (Client, AnotherClient) 또한분리되어있다. - 해결책 : SRP(Single Responsibility Principle) 을위반한다. - 효과 : Client 가그리기 () 와합성된도형구성 (Sub-) 작업을구분하지않게된다. 21
22 4. SRP(Single Responsibility Principle) Violation
SRP(Single Responsibility Principle) Violation SRP <<interface>> IComposite Client <<interface>> IShape SRP +Add(IShape*) +Remove(IShape*) AnotherClient RectangleShape EllipseShape CompositeShape +Add(IShape*) +Remove(IShape*) SRP 위반구현 23 Client RectangleShape +Add(IShape*) +Remove(IShape*) <<interface>> IShape +Add(IShape*) +Remove(IShape*) EllipseShape +Add(IShape*) +Remove(IShape*) SRP 위반 CompositeShape +Add(IShape*) +Remove(IShape*)
SRP(Single Responsibility Principle) Violation <<interface>> IShape SRP 위반 Client +Add(IShape*) +Remove(IShape*) RectangleShape +Add(IShape*) +Remove(IShape*) EllipseShape +Add(IShape*) +Remove(IShape*) CompositeShape +Add(IShape*) +Remove(IShape*) 24 class RectangleShape : IShape public: virtual void Add(IShape* pshape) throw _T( no implement ); // nothing } virtual void Remove(IShape* pshape) throw _T( no implement ); // nothing } virtual void Draw(const Graphics& g) // 그리기구현 } }; 불필요한메소드재정의 class EllipseShape : IShape public: virtual void Add(IShape* pshape) throw _T( no implement ); // nothing } virtual void Remove(IShape* pshape) throw _T( no implement ); // nothing } virtual void Draw(const Graphics& g) // 그리기구현 } }; 예외로인하여 LSP 를위반하게된다. ( 예외로파생클래스는기반클래스로치환할수없기때문에 ) 즉, 다형성획득이어려워지므로 OCP 또한준수하기힘들게된다. (LSP 위반으로인해 )
SRP(Single Responsibility Principle) Violation 불필요한메소드재정의제거하기 Hook Method 구현 Client SRP 위반 <<abstract>> Shape <<hook>> +Add(Shape*) +Remove(Shape*) class Shape public: virtual void Draw(const Graphics& g) = 0; }; // Hook Method virtual void Add(Shae* pshape) } virtual void Remove(Shape* pshape) } RectangleShape class RectangleShape : IShape public: virtual void Draw(const Graphics& g) // 그리기구현 } }; EllipseShape CompositeShape +Add(Shape*) +Remove(Shape*) 25
26 5. Design Pattern
Design Pattern 요구사항 : 그리기 : Rectangle, Ellipse Sub- : 합성 ( 合成 ) 된도형 Design Pattern (Decorator) RectangleShape <<interface>> IShape EllipseShape DecoratorShape #DecoratorShape(IShape*) : 도형 () 관리 CompositeShape : 합성 ( 合成 ) 된도형 27 : 그리기 : Rectangle, Ellipse Sub- : 합성 ( 合成 ) 된도형 : 도형 () 관리 : 합성 ( 合成 ) 된도형 OOD 원칙 ( : Sub- = N : 1) SRP 위반 RectangleShape RectangleShape <<interface>> IShape EllipseShape SRP SRP <<abstract>> Shape <<hook>> +Add(Shape*) +Remove(Shape*) EllipseShape <<interface>> IComposite +Add(IShape*) +Remove(IShape*) CompositeShape +Add(IShape*) +Remove(IShape*) SRP 위반 CompositeShape +Add(Shape*) +Remove(Shape*)
Design Pattern <<abstract>> Shape <<hook>> +Add(Shape*) +Remove(Shape*) Component RectangleShape Leaf Composite EllipseShape Leaf CompositeShape +Add(Shape*) +Remove(Shape*) Composite Component : 계층구조의모든객체를표현하는인터페이스혹은추상클래스 Composite : 다른컴포넌트를포함할수있는컴포넌트. 서브컴포넌트가 Leaf인지 Composite인지알지못한다. Leaf : 독립형컴포넌트. 다른컴포넌트를포함하지못한다. 컨테이너 / 컨텐츠 ( 전체 / 부분 ) 관계를나타내는런타임객체구조를공통인터페이스를구현하는객체의집합으로조직화한다. 인터페이스를구현하는객체중일부는독립형객체를정의하고, 일부는인터페이스를준수하는다른객체를담을수있는컨테이너를정의한다. 이때컨테이너는컨테이너를포함할수있다. 28 출처 : 실전코드로배우는실용주의디자인패턴 ( 사이텍미디어, 송치형 )
29 6. Class Diagram in Practice
Class Diagram in Practice Client +Draw() <<abstract>> Shape <<hook>> +Add(Shape*) +Remove(Shape*) RectangleShape EllipseShape CompositeShape +Add(Shape*) +Remove(Shape*) C++ Program Code 로표현해보자! 30
Class Diagram in Practice class Shape public: Shape(); virtual ~Shape(); 31 RectangleShape <<abstract>> Shape <<hook>> +Add(Shape*) +Remove(Shape*) EllipseShape public: virtual void Draw(const Graphics& g) = 0; }; // Hook Method virtual void Add(Shape* pshape) } virtual void Remove(Shape* pshape) } class RectangleShape : public Shape public: RectangleShape(); virtual ~RectangleShape(); public: virtual void Draw(const Graphics& g) // 그리기구현 } }; class EllipseShape : public Shape public: EllipseShape(); virtual ~EllipseShape(); public: virtual void Draw(const Graphics& g) // 그리기구현 } };
Class Diagram in Practice <<abstract>> Shape class CompositeShape : public Shape public: CompositeShape(); virtual ~CompositeShape(); private: list<shape*> m_plist; <<hook>> +Add(Shape*) +Remove(Shape*) CompositeShape +Add(Shape*) +Remove(Shape*) public: virtual void Draw(const Graphics& g) list<shape>::iterator it = m_plist.begin(); while(it!= m_plist.end()) // 그리기위임 it++; } } }; virtual void Add(Shape* pshape) // m_plist 에 pshape 추가구현 } virtual void Remove(Shape* pshape) // m_plist 에서 pshape 제거구현 } 32
Class Diagram in Practice Client +Draw() <<abstract>> Shape <<hook>> +Add(Shape*) +Remove(Shape*) class Client private: Shape* m_pshape; public: Client() m_pshape = new CompositeShape; 33 } } Shape* prectangle = new RectangleShape; Shape* pellipse = new EllipseShape; m_pshape->add(prectangle); m_pshape->add(pellipse); void Draw() Graphics g; } // m_pshape->draw(g); 합성 ( 合成 ) 된도형만들기
34 7. Design Pattern in Practice
Design Pattern in Practice 요구사항 : Log 데이터를 File 과 Window 모두에게출력 ( 저장 ) 한다.? 합성 ( 合成 ) 된 Stream 합성 ( 合成 ) : 둘이상의것을합쳐서하나를이룸. 요구사항재정리 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. 35
Design Pattern in Practice 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. 합성 ( 合成 ) 된 Stream 은 File 과 Window Stream 에출력 ( 저장 ) 하기위한추가책임이다. Sub- 요구사항정리 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. Sub- 36
Design Pattern in Practice /Sub- 관계 Sub- 는 의합성 ( 合成 ) 으로이루어진다. 합성 ( 合成 ) : 둘이상의것을합쳐서하나를이룸. 합성된 Stream Sub- File Window 1 개 ( 전체 ) N 개 ( 부분 ) /Sub- 관계정리 Sub- = : : N ( 부분 ) 1 ( 전체 ) 37
Design Pattern in Practice 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. Sub- Sub- 는 의추가책임이므로, 의구현은 에게위임한다. Ex. 출력 ( 저장 ) 합성된 Stream Sub- File Window 38 요구사항정리 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. Sub-
Design Pattern in Practice : 출력 ( 저장 ) 요구사항 : File, Window Sub- : 합성 ( 合成 ) 된 Stream ( : Sub- = N : 1) Composite Pattern 구현 <<abstract>> OutputStream <<hook>> +Add(OutputStream*) +Remove(OutputStream*) 39 FileOutputStream File WinOutputStream Window CompositeOutputStream +Add(OutputStream*) +Remove(OutputStream*) 합성된 Stream Sub- N 개 ( 부분 ) 1 개 ( 전체 )
Design Pattern in Practice 세부요구사항 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. Sub- 요구사항세분화 요구사항 : Log 데이터를 File 과 Window 가합성 ( 合成 ) 된 Stream 에출력 ( 저장 ) 한다. Log 데이터를동기화처리하여 Window 에출력 ( 저장 ) 한다. Log 데이터를동기화처리된 Buffered Memory 를이용하여 File 에출력 ( 저장 ) 한다. 40
Design Pattern in Practice 요구사항 : Log 데이터를동기화처리하여 Window 에출력 ( 저장 ) 한다. 동기화처리는 Log 데이터를 Window 에출력 ( 저장 ) 하기위한추가책임이다. Sub- 요구사항정리 요구사항 : Log 데이터를동기화처리하여 Window 에출력 ( 저장 ) 한다. Sub- 41
Design Pattern in Practice 요구사항 : Log 데이터를동기화처리하여 Window 에출력 ( 저장 ) 한다. Sub- Sub- 는 의추가책임이므로, 의구현은 에게위임한다. Ex. 출력 ( 저장 ) 동기화처리 Sub- Window 42 요구사항정리 요구사항 : Log 데이터를동기화처리하여 Window 에출력 ( 저장 ) 한다. Sub-
Design Pattern in Practice 요구사항 : 출력 ( 저장 ) : File, Window Sub- : 합성 ( 合成 ) 된 Stream, 동기화처리 ( : Sub- = N : 1) ( : Sub- = 1 : N) Decorator Pattern 구현 <<abstract>> OutputStream <<hook>> +Add(OutputStream*) +Remove(OutputStream*) 43 FileOutputStream File WinOutputStream Window CompositeOutputStream +CompositeOutputStream(OutputStream*) +Add(OutputStream*) +Remove(OutputStream*) SyncOutputStream +SyncOutputStream(OutputStream*) #SetSync() #ResetSync() 합성된 Stream Sub- 책임구분 (/Sub- 구분 ) 동기화처리 Sub-
Design Pattern in Practice 요구사항 : Log 데이터를동기화처리된 Buffered Memory 를이용하여 File 에출력 ( 저장 ) 한다. 동기화처리는 Buffered Memory 를사용하기위한추가책임이다. Sub- Buffered Memory 는 File 출력 ( 저장 ) 속도향상을위한추가책임이다. 44 요구사항정리 Sub- 요구사항 : Log 데이터를동기화처리된 Buffered Memory 를이용하여 File 에출력 ( 저장 ) 한다. Sub- Sub-
Design Pattern in Practice 요구사항 : Log 데이터를동기화처리된 Buffered Memory 를이용하여 File 에출력 ( 저장 ) 한다. Sub- Sub- Sub- 는 의추가책임이므로, 의구현은 에게위임한다. Ex. 동기화처리 Sub- 출력 ( 저장 ) Buffered Memory Sub- File 45 요구사항정리 요구사항 : Log 데이터를동기화처리된 Buffered Memory 를이용하여 File 에출력 ( 저장 ) 한다. Sub- Sub-
Design Pattern in Practice 요구사항 : 출력 ( 저장 ) : File, Window Sub- : 합성 ( 合成 ) 된 Stream, 동기화처리, Buffered Memory ( : Sub- = N : 1) ( : Sub- = 1 : N) <<abstract>> OutputStream <<hook>> +Add(OutputStream*) +Remove(OutputStream*) Decorator Pattern 구현 46 FileOutputStream File WinOutputStream Window CompositeOutputStream +CompositeOutputStream(OutputStream*) +Add(OutputStream*) +Remove(OutputStream*) SyncOutputStream +SyncOutputStream(OutputStream*) #SetSync() #ResetSync() 동기화처리 Sub- BufferedOutputStream 합성된 Stream Sub- 책임구분 (/Sub- 구분 ) +BufferedOutputStream(OutputStream*, UINT) #DoWrite(const void*, UINT) #SetFlash() Buffered Memory Sub-
Design Pattern in Practice /Sub- 관계 합성된 Stream Sub- 1 개 ( 전체 ) 동기화처리 Sub- N 개 Window 1 개 출력 ( 저장 ) 동기화처리 Sub- Buffered Memory Sub- File Decorator Pattern : Sub- = 1 : N Composite Pattern : Sub- = N : 1 N 개 1 개 N 개 ( 부분 ) 47
Design Pattern in Practice File 출력 ( 저장 ) File 과 Window 출력 ( 저장 ) 48 Log* m_plog; OutputStream* pfile = new FileOutputStream; OutputStream* pbuffered = new BufferedOutputStream(pFile); OutputStream* psync = new SyncOutputStream(pBuffered); m_plog->setoutputstream(psync); Code Reuse void Client::Log( ) m_plog->write(lpbuf, nlen); } 재사용가능한설계 Log* m_plog; OutputStream* pstream = new CompositeOutputStream; // Window OutputStream* pwin = new WinOutputStream; OutputStream* psyncwin = new SyncOutputStream(pWin); pstream->add(psyncwin); // File OutputStream* pfile = new FileOutputStream; OutputStream* pbuffered = new BufferedOutputStream(pFile); OutputStream* psyncfile = new SyncOutputStream(pBuffered); pstream->add(psyncfile); m_plog->setoutputstream(pstream); Open-Closed Principle 확장에대해열려있고, 수정에는대해닫혀있다
Design Pattern in Practice Pattern Summary Log +SetOutputStream(OutputStream*) Context <<abstract>> OutputStream <<hook>> +Add(OutputStream*) +Remove(OutputStream*) Strategy Component Component Composite Strategy FileOutputStream WinOutputStream CompositeOutputStream 49 Concrete Strategy Concrete Component Leaf Decorator +CompositeOutputStream(OutputStream*) Concrete Strategy +Add(OutputStream*) Concrete Component +Remove(OutputStream*) Leaf Concrete Strategy Decorator Composite SyncOutputStream +SyncOutputStream(OutputStream*) #SetSync() #ResetSync() Concrete Decorator BufferedOutputStream +BufferedOutputStream(OutputStream*, UINT) #DoWrite(const void*, UINT) #SetFlash() Concrete Decorator
50 8. Summary
Summary Composite Pattern Decorator Pattern SRP <<interface>> IOutputStream SRP 위반 <<abstract>> OutputStream <<hook>> +Add(OutputStream*) +Remove(OutputStream*) VS. FileOutputStream DecoratorOutputStream FileOutputStream WinOutputStream CompositeOutputStream #DecoratorOutputStream(IOutputStream*) +CompositeOutputStream(OutputStream*) +Add(OutputStream*) +Remove(OutputStream*) 1 개 SyncOutputStream BufferedOutputStream N 개 1 개 +SyncOutputStream(IOutputStream*) #SetSync() #ResetSync() +BufferedOutputStream(IOutputStream*, UINT) #DoWrite(const void*, UINT) #SetFlash() : Sub- = N : 1 /Sub- 관계정리 VS. N 개 : Sub- = 1 : N ( 조합 ) (Sub- 추가 ) 51
Summary 설계는단순히클래스차원만이아니라, 객체차원으로도접근할수있어야한다. Ex. 객체의메시지흐름 합성된 Stream Sub- 1 개 ( 전체 ) 동기화처리 Sub- N 개 Window 1 개 출력 ( 저장 ) 동기화처리 Sub- Buffered Memory Sub- File N 개 1 개 N 개 ( 부분 ) 52