카테고리 없음 / / 2021. 4. 28. 12:59

소프트웨어공학 9주차 - 디자인 패턴


디자인 패턴이란?

  • 자주 사용하는 설계 형태를 정형화해서 이를 유형별로 설계 템플릿을 만들어 둔 것.
  • 많은 개발자들이 경험상 체득한 설계 지식을 검증하고 이를 추상화하여 일반화한 템플릿
  • 동일한 문제 유형에 대해서는 그 해결 방법에 대한 지식이나 노하우가 패턴 형태로 충분히 일반화된 것.

클래스 패턴 - 클래스와 서브 클래스 이용해서 컴파일 타임에 역할 결정

객체 패턴 - 동적으로, 런 타임에 역할 결정(좀 더 유용한 사용 가능)

  • Class Pattern: Factory Method, Adapter, Templte Method, Iterator
  • Object Pattern: Adapter, Class Pattern을 제외한 나머지 패턴

생성 패턴: 인스턴스를 만드는 과정을 추상화하고, 구체적으로 어떤 클래스로부터 언제, 어떻게, 어디에 생성할 건지에 대한 책임을 서브 클래스에 이관

  • Factory Method: 대행 함수(Factory Method)를 통한 객체 생성. 인스턴스 생성 결정은 서브 클래스
  • Abstract Factory: 합성 객체를 만들 때 사용. 제품군(Product Family)별 객체 생성
  • Singleton: Class 인스턴스가 하나만 만들어지고 그 인스턴스에 전역 접근

구조 패턴

  • Adapter(Class & Object 패턴 모두 제공): 기존 모듈 재사용을 위한 인터페이스 변경
  • Composite: 객체 간의 부분-전체 관계 형성 및 관리. 재귀적 합성 이용
  • Decorator: 객체의 기능을 동적으로 추가/삭제
  • Facade: 서브 시스템에 대한 통합된 인터페이스 제공
  • Proxy: 대체(대리자) 객체를 통한 작업 수행

행위 패턴 - 클래스와 객체가 상호작용 하는 방법 정의 및 책임 분산

  • Template Method: 상위 클래스에서 어떤 메소드의 행위에 대한 기본 골격을 결정, 하위 클래스에서 구체적 내용 정의
  • Mediator: 객체들 간의 상호작용을 객체로 캡슐화. M:N → M:1
  • Observer: 특정 클래스, 특정 객체로부터의 상태 변화를 여러 개의 객체들이 수신해서, 각각 개별적으로 이용. Publish-Subscribe. One source Multiple use.
  • Strategy: 동일 목적의 여러 알고리즘 중 필요에 따라서 선택해서 적용.


Factory Method Pattern 객체를 반환하는 메서드

  • 상위 클래스에서 객체를 생성하는 인터페이스(factory method)를 정의하고, 하위 클래스에서 인스턴스를 생성하도록 하는 방식
  • 객체를 생성하는 시점은 알지만 어떤 타입의 클래스로부터 객체를 생성해야 할지 알 수 없을 때, 객체 생성을 하위 클래스에 위임하여 해결

  • 예를 들어, 문서 파일을 더블 클릭하면 문서 파일과 연관된 프로그램이 열리고, 그 프로그램이 파일 객체를 생성해서 사용. 즉, 운영체제가 문서 파일과 관련된 프로그램을 실행하고, 그 프로그램이 문서 파일에 대한 객체를 생성을 코딩. 여기서 사용자가 어떤 타입의 파일을 클릭했는지는 런타임에 알 수 있기 때문에 구체적인 클래스는 결정할 수 없으므로 Factory Method가 사용될 수 있다.

Singleton Pattern

  • 특정 클래스의 객체가 오직 한 개만 존재하도록 보장, 즉 클래스의 객체를 하나로 제한
    • 프로그래머의 주의에 의해서가 아닌 프로그램의 보증
  • 동일한 자원이나 데이터를 처리하는 객체가 불필요하게 여러 개 만들어질 필요가 없을 경우에 주로 사용.
  • e.g. 드라이버 객체(프린터 스풀러는 하나만 있어야만 인쇄 명령에 대해서만 메모리를 효율적인 관리가 가능하다)

  • Type A는 프로그램이 객체가 생성될 때, 생성이 되고, Type B는 최초의 요청이 있을 때 객체가 생성된다.

Abstract Factory Pattern(Factory Method 패턴보다 한 단계 더 추상화)

  • 추상적인 부품을 조합해서 추상적인 제품을 만듦.
  • 부품의 구체적인 구현은 제외하고 인터페이스(API)만을 이용해 부품을 조립하고 제품으로 완성.


구조 패턴

Composite Pattern

  • composite: '합성의', '합성물', '혼합 양식'
  • composite object: 부분-전체의 구조로 표현되는 조립 객체
    • 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 한 것
    • 재귀적 구조: 디렉토리 안에 파일 또는 다른 디렉토리(서브 디렉토리)가 존재할 수 있는 것
    • 그릇(디렉토리)과 내용물(파일)을 동일시해서 재귀적인 구조를 만들기 위한 설계 패턴

Adapter Pattern

  • 기존 클래스를 재사용할 수 있도록 중간에서 맞춰주는 역할
  • 호환성이 없는 기존 클래스의 인터페이스를 변환해 사용할 수 있도록 해준다.
  • e.g. 대부분의 온라인 쇼핑몰에서 결제할 때, 다양한 결제 수단을 제공한다. 결제 수단별로 결제 수단들이 제공하는 인터페이스를 호출하기 위해서 코드를 일일이 작성할 수 없으니, 중간에 어댑터를 두고 바꿔서 사용

  • object 방식은 Adapter 클래스를 만들 때, adaptee class의 객체를 composite 방식으로, 즉 필드 멤버로 가지고 있게 한다. 클라이언트가 Target interface를 통해서 Adapter 객체를 사용해 targetMethod1()을 호출하면 필드 멤버로 가지고 있는 adaptee 객체의 methodA, B, C 호출

  • 클라이언트가 사용할 수 있는 메소드는 printWeak()와 printStrong()뿐.
  • 단점은 adpater를 상속받아서 만들어야 하니까, 다른 adaptee를 사용하려면 새로운 adapter를 만들어야 한다. 즉, adaptee마다 adapter를 만들어야 한다.
  • 하나의 어댑터에 여러 개의 어댑티를 연결해서 사용 가능하다
  • 위임 방식이므로 기능을 재정의 할 수는 없다!

Decorator Pattern

  • 기능 확장이 필요할 때 상속의 대안으로 사용(상속을 사용하려면 특정 클래스를 정의하고 상속을 받으면, 그 클래스를 사용하고 싶으면 동적인 기능 추가가 아닌 정적인 기능 추가밖에 안 된다)
  • e.g. 게임 아이템를 강화하면 기능은 그대로인데 능력치가 올라간 경우를 생각해보자.
  • 메서드 호출의 return value에 변화를 주기 위해 중간에 decorator(장식)를 두는 패턴

  • Component: interface를 구현한 클래스 → 클라이언트(오리지널 아이템이라고 생각)
  • 핵심은 decorate 된 것을 클라이언트는 모르면 좋겠어
  • decorator는 실제 서비스와 같은 이름의 메서드를 구현. 이때 인터페이스를 사용한다.
  • decorator는 실제 서비스에 대한 참조 변수를 가진다.
  • decorator는 실제 서비스의 같은 이름을 가진 메서드를 호출하고, 그 return value에 장식(?)을 더해 클라이언트에게 반환

Facade Pattern

  • Facade: '건물의 앞쪽 정면(전면)
  • 몇 개의 클라이언트의 클래스와 서브 시스템의 클라이언트 사이에 facade라는 객체를 둠으로써 복잡한 관계를 정리(구조화)한 것
  • 모든 관계가 전면에 세워진 facade 객체를 통해서만 이루어질 수 있게 단순한 인터페이스를 제공하는 것(단순한 창구 역할)
  • facade를 도입함으로써 결합도가 낮아져서, 의존도가 떨어진다.

Proxy Pattern

  • 위 코드를 보면 Decorator 패턴과 굉장히 유사함을 알 수 있는데, Decorator 패턴과의 차이점은 Proxy 패턴은 요청에 대한 응답을 할 때 장식을 하지 않고 return한다.


행위 패턴

Observer Pattern

  • 어떤 클래스에서 변화가 일어났을 때, 이 소식을 전달받아서 다른 클래스에게 통보해주는 것
  • e.g. 엑셀에서 데이터를 시트에서 집어넣고, 차트를 그렸다고 가정하자. 만약 시트의 데이터를 변경하면 차트의 데이터도 같이 변경된다 ← 옵저버 패턴

    • getNumber(): 상태를 읽어가도록 하는 메소드
    • excute(): 상태를 발행하는 메소드
    • o.update(this)에서 this를 왜 줄까? → ① 관찰 대상의 상태가 변경됐을 때, 관찰 대상이 직접 상태가 바뀌었다가 데이터를 주는 방식 ② 옵저버가 상태 변화를 감지하고, 상태를 읽어가는 방식이 있지만 객체들 간의 독립성을 위해서 ②번 방식이 더 효율적이다. 위 코드 역시 getNumber 메소드로 옵저버가 상태를 읽어간다.

    Strategy Pattern

    • 다른 방법으로 문제를 해결할 수 있는 알고리즘으로 쉽게 교체할 수 있게 도와줌
    • 클라이언트가 알고리즘이 적용되는 상황(context)을 알고 있어야 함.

Template Method Pattern (class pattern)

  • 상위 클래스에서 추상적으로 표현하고 구체적인 내용은 하위 클래스에서 결정!

  • Animal 클래스를 abstract으로 하는 이유는 로직을 정의하는 부분은 concrete method로 정의하고 변화가 되는 부분만 override.
  • Template Method
    • playWithOwner(): 변경이 되면 안 되는 메서드
    • play(): 변경이 필요한 메서드 ← 꼭 변경이 되어야 하는 부분
    • runSomething(): 변경이 돼도 되고 안 돼도 되고... hook 메서드

Mediator Pattern

  • 다수의 객체들 사이에 다수의 관계가 존재할 때 중재자 역할의 객체를 이용해 관계를 축소시키는 패턴
  • e.g. radio 버튼을 예를 들면, 라디오 버튼을 여러 개 만들면 무조건 라디오 그룹에 add를 시켜야 한다. 무조건적인 add를 하는 이유는 radio button 간에 배타적 선택이 되어야 하기 때문이다. 만약 radio group 없이 각각의 라디오 버튼만 있다면 하나의 라디오 버튼이 선택될 때마다, 다른 라디오 버튼에게 선택된 사실을 알려줘야 해서 비효율성이 증가하므로 radio group이라는 mediator가 있으면 비교적 효율적 관계 정립이 가능하다.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유