head first design pattern에 정의된 내용.
- strategy pattern : strategy pattern 은 알고리즘군을 정의(인터페이스)하고 각각을 캡슐화하여 교환해서 사용할 수 있도록 만든다. 이를 이용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.
- 예제 : 연못의 오리 게임. Duck 이라는 super class를 만들고 이를 상속 받은 여러 종류의 오리 class가 있다. 원래 Duck class에는 없는 기능을 넣을 려면 어떻게 해야 하는가?
- 단순 답변 : Duck class에 특정 기능의 함수를 넣어준다. 하지만 이는 Duck class를 상속 받은 클래스 모두에게 이 기능이 생기게 된다. 만약 특정 derived class는 이 기능이 변형되어야 한다면?
- strategy pattern : 위 문제는 함수 오버라이딩으로 가능하기는 하지만.. 이보다는 변형 가능한 것들을 하나의 인터페이스로 만든 다음 이것을 Duck class 의 맴버 변수로 넣는다. 구현은 이 인터페이스를 상속받는 여러 클래스들에서 구현.
- observer pattern : observer pattern 에서는 한 객체(subject)의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다 의존성을 정의한다.
- 예제 : 기상스테이션 예제로 WeatherStation이라는 클래스가 있고 이 클래스에서는 기상변화를 관찰 한다. 기상 정보는 실시간으로 WeatherData라는 클래스의 객체로 넘어가고 이때 WeatherData 객체는 이 업데이트된 정보를 각각의 Display 객체들에게 통보해야 한다.
- observer pattern : Subject 라는 인터페이스를 만들고 그 안에는 Observer 라는 interface를 갖고 있다. WeatherData 클래스는 Subject 인터페이스를 구현하고 있다. Observer 는 여러 Display 클래스들에 의해 구현되어 지고 이 Display 클래스들은 WeatherData 클래스 객체를 맴버 변수고 갖고 있어서 생성자가 호출될 때 WeatherData 객체를 넘겨 받아서 넘겨받은 WeatherData의 add 함수를 호출해서 WeatherData의 observer 맴버 변수 배열에 Display 자기 자신을 등록한다.
- Decorator pattern : decorator pattern에서는 객체에 추가적인 요건을 동적으로 첨가한다. 데코레이터는 서브클래스를 만드는 것을 통해서 긴능을 유연하게 확장할 수 있는 방법을 제공한다.
- 예제 : 스타버즈라는 커피숍의 주문 시스템을 만든다. 각 매뉴들을 표현하고 가격을 구현해야 한다.
- 단순 답변 : Beverage라는 베이스 클래스를 만들고 새로 생기는 메뉴마다 이 슈퍼 클래스를 상속받는 서브 클래스를 만든다. 아니면 베이스 클래스에다가 서브 클래스에서 쓸 맴버 변수들을 포함시킨다. 이러한 경우 서브 클래스가 엄청 많아진다거나 혹은 서브 클래스가 필요하지도 않은 많은 맴버 변수들을 상속받게 된다.
- decorator pattern : 문제를 파악해보면 DarkRoast, HouseBlend, Decaf는 기본이 되는 음료가 되고 여기에다가 Mocha나 Whip (휘핑크림) 등은 decorator가 되겠다. 모든 음료의 기본이 되는 베이스 가상 클래스인 Beverage를 정의 하고 각종음료(DarkRoast, HouseBlend, Decaf)는 이를 상속하고 구현하는 구상 클래스가 되겠다. 그리고 decorator들(Mocah, Whip) 역시 Beverage 가상 클래스를 상속하게 한다. 이것의 목적은 Beverage로 부터 행동을 상속 받기 위함이 아니라 decorator의 형식과 각종 음료의 형식을 맞취기 위한 것이다. 확장되는 행동들은 decorator 안에 구현하고 decorator 안에는 또한 Beverage를 구성 요소로 갖는다. 결론적으로 기본음료를 decorator가 감싸고 이 감싼 객체를 또다른 decorator가 감싸는 형식으로 구현하는 것이다.
디자인 원칙
- 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리 시킨다.
- 구현이 아닌 인터페이스에 맞춰서 프로그래밍한다.
- 상속보다는 구성을 활용한다.
- 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.
No comments:
Post a Comment