Object-Oriented Design Agile for Software Development Story 4. 작 성 자 : 고형호 메 일 : hyungho.ko@gmail.com 홈페이지 : 최초작성일 : 2007.06.12 최종작성일 : 2007.08.31 1
2 Goal Flexibility & Reusability
Content 1. Flexibility & Reusability Definition 2. Interface 3. Inheritance 4. Summary 3
4 1. Flexibility & Reusability Definition
Flexibility & Reusability Definition Flexibility is the popular term for the ability to easily bend an object or the ability to adapt to different circumstances. 유연성은어떤객체를원하는대로손쉽게변경할수있는능력을말하는데, 때로는한객체가서로다른여러환경에적응하는능력을가리키기도한다. Reusability is the likelihood a segment of source code can be used again to add new functionalities with slight or no modification. 재사용성이란새로운기능을추가하기위해, 기존소스코드의일부를매우최소로변경하거나또는전혀수정없이다시사용할수있는가능성을말한다. 유연한소프트웨어 From the user's point of view, flexible software accommodates varying conditions or requirements. 사용자의관점에서보았을때, 유연한소프트웨어는계속변화하는조건이나요구사항들을수용한다. From a developer's point of view, flexible software can be modified or extended with ease. 개발자의관점에서보았을때, 유연한소프트웨어는쉽게변경하거나확장할수있는것이다. 5 ( 출처 : Object Design)
6 2. Interface
Interface <<interface>> IShape IShape* pshape = new Rectangle; +Draw(const Graphics&) Rectangle +Draw(const Graphics&) Object Object s Type (Object 의인터페이스만을정의한다.) Object s Class (Object 의구현을정의한다.) 정리 Interface* pobject = new Implementation; An object's interface characterizes the complete set of requests that can be sent to the object. Object 의 Interface 는 Object 가받아서처리할수있는오퍼레이션들의집합이다. ( 출처 : GoF Design Patterns) 7
Interface Interface* pobject = new Implementation; C++ 의 class는 Interface와 Implementation을구분하지않는다. (Object s Type) (Object s Class) 올바른 Class Definition Shape +Draw(const Graphics&) Rectangle Ellipse 1. Rectangle* pshape; (Implementation) pshape = new Shape; ( 컴파일에러 ) pshape = new Rectangle; pshape = new Ellipse; ( 컴파일에러 ) ( X ) 구현종속다형성획득에러 +Draw(const Graphics&) Rectangle +Draw(const Graphics&) <<interface>> IShape +Draw(const Graphics&) +Draw(const Graphics&) Ellipse +Draw(const Graphics&) 2. Shape* pshape; (Implementation) pshape = new Shape; pshape = new Rectangle; pshape = new Ellipse; 3. IShape* pshape; (Interface) pshape = new IShape; ( 컴파일에러 ) pshape = new Rectangle; pshape = new Ellipse; ( ) 구현종속 ( O ) 8
Interface Interface* pobject = new Implementation; Inheritance Inheritance 인터페이스를상속 (Interface Inheritance) 구현코드를상속 (Implementation Inheritance) Meaning Meaning 객체가다른곳에서사용될수있음을의미한다. (Object 의 Type 이기때문에 ) 구현코드의재사용을의미한다. 9
Interface Log +SetOutputStream(IOutputStream*) delegation Has-a 관계 (Log has a IOutputStream.) <<interface>> IOutputStream Interface( 올바른 Class Definition) class Log private: IOutputStream* m_poutputstream; public: void SetOutputStream(IOutputStream* poutputstream) // do something m_poutputstream = poutputstream; } }; void Write(const void* lpbuf, UINT nlen) // do something m_poutputstream->write(lpbuf, nlen); } 런타임에 Write 구현이변경된다 (Concrete Class 가변경되므로 ). 런타임에 IOutputStream 인터페이스를상속받는임의의 Concrete Class 로변경할수있다. 10
Interface class Log private: IOutputStream* m_poutputstream; public: void SetOutputStream(IOutputStream* poutputstream) // do something m_poutputstream = poutputstream; // Dynamic Binding } }; void Write(const void* pdata, UINT nlen) // do something m_poutputstream->write(pdata, nlen); } 올바른 Class Definition 효과 1. 요청과요청을처리할객체를런타임에결정할수있다 ( 동적바인딩 : Dynamic Binding). (Log::Write) (m_poutputstream) (Log::SetOutputSream) 2. Log 는인터페이스에의존하므로 Concrete Class 를알필요가없다. 3. 즉, Log 는 Concrete Class 변화의영향을받지않는다 ( 구현종속성제거 ). 11
Interface Log +SetOutputStream(IOutputStream*) delegation Has-a 관계 <<interface>> IOutputStream class Log private: IOutputStream* m_poutputstream; (Interface) }; Programming to Interface, not an Implementation. 구현이아닌인터페이스에따라프로그래밍하자. 올바른 Class Definition을하자 (Interface* pobject = new Implementation;). 의존관계역전의원칙 (DIP: Dependency Inversion Principle) 인터페이스는 IOutputStream을사용하는곳 (Log) 과구현하는곳 (Concrete Class) 를분리시킨다. 클라이언트는구체클래스가아닌인터페이스에의존하여변화에대처한다. 12
Interface My rule of thumb is that as much as 80 percent of my code should be written in terms of interfaces. 나의경험법칙에따르면대부분코드의 80% 는인터페이스의관점에서재작성되어야한다. Allen Holub 13 출처 : 실전코드로배우는실용주의디자인패턴 ( 사이텍미디어, 송치형 )
14 3. Inheritance
Inheritance C++ for Reusability Implementation Inheritance Composition(Aggregation, Association) with Interface Inheritance Template(Generic) 15
Inheritance Implementation Inheritance White-Box Reuse 상속을받으면, 기반클래스의내부가파생클래스에게공개되기때문이다. 은닉 (Hiding) 이파괴된다. 구현에종속된다. 결합도를증가시킨다. 결론 유연성 (Flexibility) 과재사용성 (Reusability) 을감소시킨다. 16
Inheritance Implementation Inheritance 문제점 : 유연성과재사용성을감소시킨다. Ex. 상속한구현이새로운문제에맞지않을때, 기반클래스를재작성해야하거나다른것으로대체하는일이생기게된다. 그로인해, 모든파생클래스들은재컴파일되어야한다. 원인 : 구현종속 해결책 : 구현종속제거 17
Inheritance Interface Inheritance Black-Box Reuse 객체의내부는공개되지않고인터페이스를통해서만재사용되기때문이다. 은닉 (Hiding) 이유지된다. 구현에종속되지않는다. 결합도를감소시킨다. 결론 유연성 (Flexibility) 과재사용성 (Reusability) 을증가시킨다. 18
Inheritance 요청수신객체 요청위임자 (Delegate) Client 서비스요청 Log +SetOutputStream(IOutputStream*) delegation Has-a 관계 <<interface>> IOutputStream class Log private: IOutputStream* m_poutputstream; public: void SetOutputStream(IOutputStream* poutputstream) m_poutputstream = poutputstream; //dynamic binding } }; void Write(const void* lpbuf, UINT nlen) m_poutputstream->write(lpbuf, nlen); //delegation } 19 위임 (Delegation) : 수신객체가요청의처리를위임자 (Delegation) 에게보낸다. 위임의목적 위임을사용해서인터페이스를재사용할수있다. (Composition, Aggregation 또는 Association 관계에서 )
Inheritance Client Log +SetOutputStream(IOutputStream*) delegation Has-a 관계 <<interface>> IOutputStream class Log private: IOutputStream* m_poutputstream; public: void SetOutputStream(IOutputStream* poutputstream) m_poutputstream = poutputstream; //dynamic binding } void Write(const void* lpbuf, UINT nlen) m_poutputstream->write(lpbuf, nlen); //delegation } }; FileOutputStream DBOutputStream 인터페이스상속을통해인터페이스를구현한다. 위임과인터페이스상속 인터페이스상속기반으로위임을사용하여재사용가능한설계를할수있다. (Delegation 은 Composition, Aggregation 또는 Association 관계를통해 ) 20
Inheritance Log +SetOutputStream(IOutputStream*) delegation Has-a 관계 <<interface>> IOutputStream class Log private: IOutputStream* m_poutputstream; public: void SetOutputStream(IOutputStream* poutputstream) m_poutputstream = poutputstream; //dynamic binding } void Write(const void* lpbuf, UINT nlen) m_poutputstream->write(lpbuf, nlen); //delegation } }; FileOutputStream DBOutputStream 21 Favor Object Composition(with Interface Inheritance) over Class Implementation. (Implementation Inheritance) 구현상속 (Is-a 관계 ) 보다는 ( 인터페이스상속을기반으로한 ) 객체합성 (Has-a 관계 ) 을선호하자. 개방폐쇄원칙 (OCP: Open-Closed Principle) 인터페이스상속으로확장에대해열려있고, 수정에는대해닫혀있다. 결론 유연성 (Flexibility) 과재사용성 (Reusability) 이증가되므로재사용가능한설계를할수있다.
Summary Design Patterns leaves the debates about code reuse behindand shows the real key to software reuse: reusable design. 디자인패턴은코드재사용에대한논쟁을초월하여재사용가능한설계가진정한소프트웨어재사용의핵심임을보여주고있다. Steve Vinoski, Software Architect 22 ( 출처 : GoF Design Patterns)
23 4. Summary
Summary 재사용의목적은 Implementation Inheritance(Is-a 관계 ) 을기반으로한구현코드재사용이다. ( X ) Interface Inheritance 을기반으로한재사용가능한설계 (Has-a 관계 ) 이다. ( O ) 24
Summary Programming to Interface, not an Implementation. Favor Object Composition(with Interface Inheritance) over Class Implementation. (Implementation Inheritance) 재사용의목적은재사용가능한설계이다. 25