1. Design patterns란?
소프트웨어 개발 중 특정 문맥에서 발생할 수 있는 문제에 대한 solution을 나타내는 패턴으로, static / dynamic structure와 key participants간의 collaboration으로 이 문제에 대한 솔루션을 제공한다. 이렇게 패턴을 정의함으로써 이미 성공한 software architecture & design를 재사용 할 수 있다는 장점이 있다. Design Patters은 Creational patterns / Structural patterns / Behavior patterns로 분류 될 수 있다. 각 pattern이 어떤 의미를 갖고, 어떤것이 포함되는지 살펴보자.
1-1. Design pattern 분류
1-1-1. Creational patterns
class와 object의 초기화 / 설정을 담당하는 패턴이다.
1-1-2. Structural patterns
class의 interface와 implementation의 decoupling(interface정의하여 공통된 부분을 일반화)을 담당하는 패턴이다.
1-1-3. Behavior patterns
class의 집합간의 dynamic interaction을 담당하는 패턴이다.
이에는 다음과 같은 것들이 포함된다.
이제 이것들을 어떻게 정의할 지 알아보자.
1-2. Design pattern의 원칙
디자인 패턴은 3가지의 원칙으로 나눌 수 있다.
1. implementation으로 부터 interface을 분리하라
2. common interface를 통해 variable implementation을 허용하라
3. interface와 implementation에서 어떤 것이 common(Stable, 변하지 않음, closed)이고 어떤것이 variable(Unstable, to be solved, open)인지 결정하라
1-2-1. Open / Closed Principle
3번에서 open과 close에 대한 개념을 자세히 살펴보자. 이를 Open / Closed Principle이라고 부르는데, common feature와 variable feature를 결정하는 것이다. 이렇게 이분화 하는 이유는, 불완전한 variation이 유저에게 application customization을 어렵게 만들기 때문이다. component를 다음과 같은 원칙으로 open과 closed로 이분화 할 수 있다.
1. Variable feature은 customization과 extension에 대해 Open되어야 한다.
2. Common feature은 modification에 대해 Closed되어야 한다.
이러한 원칙들을 이용하여 정의한 Design pattern의 예시들을 지금부터 살펴보자.
(1. Composite Design Pattern / 2. Observer Design Pattern / 3. Strategy Design Pattern / 4. Template Method Design Pattern)
2. Composite Design Pattern
object를 tree structure로 compose(구성, 합성)하여 part-whole hierarchies로 표현하자(recursive composition). 이렇게 compose함으로써 클라이언트에게 individual object와 object의 compositions을 동일한 방식(uniformly)으로 처리할 수 있게 해줄 수 있다. 이는 recursive composition이라고도 불린다. 왜 위의 장점이 중요한 것인지 예를 들어가며 이해해보자.
2-1. Composite Design Pattern의 적용 동기
간단한 component들을 이용해 복잡한 diagram을 그려주는 어플리케이션이 있다고 가정하자. 유저가 component를 묶어 더 큰 compoent를 형성할 수 있고, 그렇게 만들어진 component는 또 다른 component에 소속될 수 있다. 문제는 여기서 발생한다. user는 primitive와 container object를 구분 없이 다루지만, 구현 시 primitive(선, 사각형, 점 등)와 container objects(diagram, 사진 등)을 구현하기 위해서 각기 다른 code를 써야 한다는 문제점이 발생한다. 이는 어플리케이션을 더 복잡하게 만드는 문제점을 야기한다. 다음은 이를 구분할 때의 structure이다.
2-2. Composite Design Pattern의 적용
Composite pattern을 다음과 같은 경우에 사용한다.
1) 객체의 part-whole hierarchies로 표현하고자 할 때.
2) 유저가 composition object와 individual object의 차이를 무시하길 바랄때(즉, composition과 individual object를 uniform하게 다루고자 할 때)
어떻게 구조를 디자인해야 이러한 장점을 얻을 수 있을까? 다음은 Composite design pattern의 청사진이다.
각 요소들을 살펴보면서, 각 요소가 어떠한 용도로 정의되었는지, 무엇을 정의하는지 등을 알아보자.
2-3. Composite Design Pattern 요소
2-3-1. Component (2-1의 예시에서 Graphic을 의미)
Component는 composition내 object의 interface인 Component를 정의한다. 이 component는 모든 class에 대해서 일반적인(common) interface의 default behavior를 구현하며 child component에 접근 및 관리에 대한 interface를 정의한다. 선택적으로 recursive structure에서 components의 parent를 접근하는 interface를 정의하고, 적절히 구현한다.
2-3-2. Leaf (2-1의 예시에서 사각형, 선 등을 의미)
composition의 leaf object를 표현한다. 이 객체는 자식이 없으며, composition내 primitive object의 behavior를 정의한다.
2-3-3. Composite (2-1의 예시에서 Diagram, 사진 등을 의미)
children을 가진 component의 behavior를 정의한다. child components를 저장하며, component interface에서 child-related operation을 구현한다.
2-3-4. Client
Component interface를 통해 composition내의 object를 조작한다.
2-3-5. 요소간의 연결(Collaborations)
클라이언트는 composite structure 내 object와 상호작용 하기 위해서 Component class interface를 사용한다. 만약 그 객체가 leaf라면, 그 요청은 바로 처리될 것이고, 그 객체가 composite이라면 그 요청을 child component에게 forward하여 처리하게 하고, 구현에 따라 request forward 앞뒤로 additional operation을 실행할 것이다.
2-4. Composite Design Pattern의 효과
결과적으로 Composite Design pattern을 적용함으로써 우리는 primitive object와 composite object로 구성된 class hierarchies를 정의할 수 있고, 이를 이용하여 클라이언트가 더 쉽게 사용하게 되며, 새로운 component추가가 용이해진다는 장점을 취할 수 있다.
하지만 composite의 components의 type을 제한하는것을 어렵게 한다는 단점이 존재한다. (이거 질문)
make it harder to restrict the type of components of a composite
3. Observer Design Pattern
3-1. Observer Design Pattern의 적용 동기
observer design pattern은 하나의 object의 상태가 변경 되었을때 그 object에 dependent한 object가 notified되고, 자동으로 update되는 관계인 object간의 one-to-many dependency를 정의하고자 할 때 사용된다. 만약 이 pattern을 사용하지 않고 그냥 구현한다면 어떤 문제점이 생길까? 다음 예시를 살펴보자.
하나의 application data를 기반으로 각기 다른 presentation aspect를 분리하여 보여주는 어플리케이션이 존재한다고 가정하자. 이 presentation들은 class간에 연결성이 존재하지 않으면서도 서로 연관된 객체의 consistency를 유지해야한다. 이러한 경우에 observer design pattern을 사용하면 쉽게 문제를 해결할 수 있다.
3-2. Observer Design Pattern의 적용
이는 다음과 같은 조건일 때 사용한다.
1) abstraction이 하나가 여러개에 의존적(dependent)한 형태를 띌 때 -> seperate object의 이러한 상을 캡슐화 하는 것이 각각 다양성과 재사용성을 제공할 것이다
2) 하나의 object가 변할 때 다른 object도 변해야 할 때.
3) object가 다른 object들을 알지 못하더라도(추정하지 않더라도) 그 object 들에게 notify할 수 있어야 할 때
다음은 observer design pattern의 청사진이다.
3-3. Observer Design Pattern의 요소
Observer Design Pattern은 다음과 같은 요소를 갖는다.
3-3-1. Subject
Observers이 추적하고 있는 객체로, Observer object를 추가(Attach)하고 삭제(Detach)하는 기능의 interface를 제공해야 한다.
3-3-2. Observer
Notification을 update하기 위한 interface가 정의되어야 한다.
3-3-3. ConcreteSubject
관찰될 object로, ConcreteObjserver object가 관찰할 state가 저장되어 있다. state가 바뀔 때 observer들에게 notification을 전송해야 한다.
3-3-4. ConcreteObserver
관찰하는 object로, consistent한 subject의 state를 저장한다. Observer update interface를 구현하여 subject의 state와 자신의 state의 consistency를 유지해야 한다.
3-3-5. 요소간의 연결(Collaborations)
1. ConcreteSubject의 state가 변결될 때마다 observer들에게 notify한다.
이를 통해 observer들이 자신의 state가 subject state와 consistent하게 유지할 수 있다.
2. Observer가 Subject의 state 변화를 반영
ConcreateObserver들이 notify된 이후, ConcreateObserver은 subject에게 정보에 대한 query를 할 것이다. 그리고 ConcreateObserver가 전달 받은 정보를 이용하여 자신의 state를 조정한다.
이 과정을 도식화 하면 다음과 같다.
3-4. Observer Design Pattern의 결과
장점
1. Subject와 Observer간의 최소화 된 연결
이러한 분리를 통해 subject를 관찰하는 observers을 다시 사용하지 않으면서도 subject를 다시 사용할 수 있다. 또한 subject을 수정하지 않고도 Observer를 추가할 수 있다. 모든 subject는 obserber의 list를 알 수 있으면서 각 observer의 concrete class를 알 필요가 없다(왜냐하면 모든 observer가 update inferface를 구현했기 때문에). 또한 subject와 observer는 다른 abstraction layer에 존재할 수 있다.
2. event broadcasting의 지원
subject가 모든 observer들에게 notification을 보낸다. observer는 언제나 추가될 수도, 삭제될 수도 있다.
단점
1. notification의 Cascading을 야기할 수 있다.
observer는 서로에 대해서 모르기 때문에 update trigger를 반드시 조심해야한다.
2. 간단한 update interface가 변경된 item을 추론해야할 의무가 있다.
4. Strategy Design Pattern
algorithm의 family를 정의하는 방식으로, 각 algorithm을 캡슐화 하고 interchangeable하게 만든다. 이 방식은 algorithm이 그 algorithm을 사용하는 client로 부터 독립적으로 변화할 수 있게 만들어 준다. 이 pattern이 필요한 이유를 다음 예시를 살펴보면사 이해해보자
4-1. Strategy Design Pattern의 적용 동기
text stream을 줄단위로 나누는 algorithm을 생각해보자. 만약 이 application이 linebreaking code를 추가한다면 더욱 복잡해진다. 여기에 multiple linebreaking algorithm까지 지원해진다면 client는 관리가 더 크고 더 어려워질 것이다. 이처럼 다른 경우에 대해서 다른 알고리즘을 사용하는것이 쉽지 않으며, 새 알고리즘을 추가하거나 존재하는 알고리즘을 변화하는것이 어렵다.
4-2. Strategy Design Pattern의 적용
위와 같이 아래에 명시된 경우와 부합한다면 Strategy pattern을 사용하면 효율적으로 디자인할 수 있다.
1. behavior만 다른 많은 related class를 만들어야 할 때
2. 알고리즘의 변형이 필요로 할 때
3. algorithm이 사용하는 data를 client에게 노출시키고 싶지 않을 때
4. multiple conditional statements에서 많은 Behavior를 정의해야 할 때 (즉, 많은 조건문을 그대로 사용하는 대신 strategy class를 사용함으로써 related conditional branch를 옮긴다.)
4-3. Strategy Design Pattern의 요소
4-3-1. Srategy(Compositor)
모든 지원 알고리즘에 대한 common interface를 선언하는 것
context가 interface를 통해 ConcreteStrategy에 정의된 알고리즘을 호출한다.
4-3-2. ConcreteStrategy(SimpleCompositor, TeXCompositor, ArrayCompositor)
Strategy interface를 이용하는 algorithm의 구현
4-3-3. Context(Composition)
ConcreteStrategy object를 포함하는 객체
strategy object에 대한 reference(참조)를 유지하는 요소
strategy가 data에 접근하도록 interface를 제공한다.
4-3-4. Collaborations
1. Strategy와 Context가 선택된 알고리즘을 구현하기 위해서 상호작용 한다.
context가 알고리즘을 호출할 때 algorithm에 필요한 모든 데이터를 strategy에게 전달한다. 혹은, context 그 자체가 인자로써 strategy operation에 전달될 수도 있다. 이렇게 함으로써 strategy가 context에 call back을 할 수 있다.
2. Context가 클라이언트의 request를 strategy로 forward한다.
client는 종종 ConcreateStrategy object를 context에게 생성 및 전달할 수 있다. 그 이후, client는 context와만 독점적으로 상호작용한다. 클라이언트가 ConcreateStrategy class의 family로 부터 선택해야 할 경우가 존재한다.
위의 Collaboration을 기반으로, Open/Closed principle을 적용하여 structure를 다시 구성하면 다음과 같다.
4-4. Strategy Design Pattern의 결과
장점
1. 다양한 algorithm behavior를 얻기 위한 context class의 subclassing의 대안을 제공한다.
2. conditional statement를 없앨 수 있다.
3. 같은 behavior에 대해 implementation의 선택을 제공한다
단점
1. object의 수가 증가한다
2. 모든 알고리즘이 동일한 strategy interface를 사용해야한다.
5. Template Method Design Pattern
알고리즘의 skeleton을 정의하고, 일부 step을 subclass로 미룬다. 알고리즘의 전체적인 구조를 유지하면서 Subclasses이 알고리즘의 일정 step을 redefine할 수 있게 해준다.
5-1. Template Method Design Pattern의 적용 동기
method가 사용하는 operation의 순서를 정의(혹은 수정)하고 싶을 때
method가 subclass의 요구를 맞추기 위해 이러한 operation을 다양히 해야할 때
이에 대한 경우를 예시를 들어 살펴보자. 존재하는 파일을 여는 Application class와 파일 내의 정보를 표현하는 Document class를 제공하는 application framework가 있다고 가정해보자.
OpenDocument는 다음과 같이 구성될 것이다.
이러한 template method는 operation의 순서는 고정하지만, application의 subclass이 필요에 따라 이러한 step을 변경하는 것을 허가한다.
5-2. Template Method Design Pattern의 적용
Template Method Design Pattern은 다음과 같은 경우에 사용한다.
1. 알고리즘에서 변하지 않는 부분을 우선 구현하고, subclass에게 바꿀 수 있는 behavior의 구현을 맡기고자 할 때
2. subclass간의 공통된 behavior를 localize하고 common class(superclass)에 두어 반복된 코드 문제를 피하고자 할 때
3. subclass의 superclass의 operation확장을 제어하고자 할 때 - hook operation을 통해 일정 포인트에서만 확장할 수 있게 함
4. code reuse를 위한 fundamental techique이 필요할 때
구조는 다음과 같다
5-3. Template Method Design Pattern의 요소
5-3-1. AbstractClass(Application)
concrete subclass들이 구현해야 할 abstract primitive operation를 정의하는 역할을 한다.
template method를 정의하여 알고리즘의 skeleton를 구현한다. - template method는 abstractClass나 다른 객체가 정의한 operation외에도 primitive operation을 호출한다.
5-3-2. ConcreteClass(MyApplication)
subclass-specific한 step을 진행하기 위해 primitive operation을 구현한다.
5-3-3. Collaborations (연결)
ConcreteClass는 불변하는 알고리즘의 단계를 구현하기 위해서 AbstractClass에 의존한다.
다음은 Open /Closed Principle을 적용하여 structure를 재구성한 것이다.
5-4. Template Method Design Pattern의 결과
Code reuse가 가능해진다 (특히 중요 class libraries! 왜냐하면 template method는 common behavior을 통합하는 효과가 있기 때문에)
어떤 oepration이 hook(단순히 overriden이 가능한 operation)인지, 어떤 operation이 abstract operation(반드시 overridden되어야 하는 operation)인지 명시해주는 것이 중요하다.
'학교 공부 > 소프트웨어 분석 및 설계' 카테고리의 다른 글
Software Analysis and Design - ML (0) | 2021.12.05 |
---|---|
Software Analysis and Design - Software Architecture Styles (0) | 2021.12.05 |
Software Analysis and Design - Software Architecture Design (0) | 2021.12.04 |
Software Analysis and Design (0) | 2021.12.04 |
Software Analysis and Design - Functional and Data Component (0) | 2021.12.04 |