OCP 살펴보기
디자인 원칙 5: OCP(Open-Closed Principle) 클래스는 확장에는 열려 있어야 하지만, 변경에는 닫혀 있어야 한다.
데코레이터 패턴의 정의
데코레이터 패턴(Decorator Pattern)으로 객체에 추가 요소를 동적으로 더할 수 있다. 데코레이터를 사용하면 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있다.
데코레이터 패턴 UML


데코레이터 추상 클래스는 장식할 Component(구성 요소) 인스턴스 변수를 가지고 있으면서, 자신이 장식할 구성 요소와 같은 인터페이스/추상 글래스를 구현한다.
데코레이터 패턴 예제 코드
public abstract class Beverage {
String description = "제목 없음";
public String getDescription() {
return description;
}
public abstract double cost();
}
public class Espresso extends Beverage {
public Espresso() {
description = "에스프레소";
}
@Override
public double cost() {
return 1.99;
}
}
Beverage 추상 클래스를 통해 Espresso와 같은 구상 클래스들을 만들 수 있으며, 데코레이터 클래스로 감쌀 수 있다.
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public abstract String getDescription();
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 모카";
}
@Override
public double cost() {
return beverage.cost() + .20;
}
}
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 휘핑크림";
}
@Override
public double cost() {
return beverage.cost() + .10;
}
}
CondimentDecorator 추상 클래스는 Beverage 클래스를 상속하며 동시에 구성(Composition)으로 가지고 있다.
이를 통해 추상 클래스를 구현하는 Mocha나, Whip 구상 클래스가 Beverage의 메소드를 호출한 후 추가 작업을 진행하여 Beverage의 메소드를 오버라이드 하는 형태로 데코레이팅을 한다.
public class StarbuzzCoffee {
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
}
}
DarkRoast 클래스의 인스턴스인 beverage2는 Mocha와 Whip 데코레이터 클래스를 거치면서 데코레이팅된다.
이후 beverage2.getDescription()으로 호출되면 getDescription() (Whip) -> getDescription() (Mocha) -> getDescription() (Mocha) -> getDescription() (DarkRoast) 순으로 내부적으로 호출되고, 그 결과가 역순으로 반환되어 결과가 출력된다.
데코레이터가 적용된 예: 자바 I/O
java.io 패키지는 데코레이터 패턴을 바탕으로 만들어졌다. InputStream 추상 구성 요소를 구현한 FileInputStream 등의 구상 구성 요소들을 FilterInputStream이라는 추상 데코레이터를 구현하는 구상 데코레이터들이 꾸미고 있다.
데코레이터의 단점: 데코레이터를 위한 잡다한 클래스들이 많아
핵심 정리
- 디자인의 유연성 면에서 보면 상속으로 확장하는 일은 별로 좋은 선택이 아님.
- 기존 코드 수정 없이 행동을 확장해야 하는 상황도 있음.
- 구성과 위임으로 실행 중에 새로운 행동을 추가할 수 있음.
- 상속 대신 데코레이터 패턴으로 행동을 확장할 수 있음.
- 데코레이터 패턴은 구상 구성 요소를 감싸 주는 데코레이터를 사용함.
- 데코레이터 클래스의 형식은 그 클래스가 감싸는 클래스 형식을 반영함(상속이나 인터페이스 구현으로 자신이 감쌀 클래스와 같은 형식을 가짐)
- 데코레이터는 자기가 감싸고 있는 구성 요소의 메소드를 호출한 결과에 새로운 기능을 더함으로써 행동을 확장함.
- 구성 요소를 감싸는 데코레이터의 개수에는 제한이 없음.
- 구성 요소의 클라이언트는 데코레이터의 존재를 알 수 없음. 클라이언트가 구성 요소의 구체적인 형식에 의존하는 경우는 예외임.
- 데코레이터 패턴을 사용하면 자잘한 객체가 매우 많이 추가될 수 있고, 데코레이터를 너무 많이 사용하면 코드가 필요 이상으로 복잡해짐.
GitHub Code Reference: https://github.com/Krapi0314/Design_Patterns
GitHub - Krapi0314/Design_Patterns: Java Implementation of GoF's Design Patterns
Java Implementation of GoF's Design Patterns. Contribute to Krapi0314/Design_Patterns development by creating an account on GitHub.
github.com
Reference: http://www.yes24.com/Product/Goods/108192370
헤드 퍼스트 디자인 패턴 - YES24
유지관리가 편리한 객체지향 소프트웨어 만들기!“『헤드 퍼스트 디자인 패턴(개정판)』 한 권이면 충분하다.이유 1. 흥미로운 이야기와 재치 넘치는 구성이 담긴 〈헤드 퍼스트〉 시리즈! 하나
www.yes24.com
'객체지향 및 기반 언어 > 디자인 패턴' 카테고리의 다른 글
[Design Pattern] Chapter 06 커맨드 패턴 (0) | 2022.10.02 |
---|---|
[Design Pattern] Chapter 05 싱글턴 패턴 (0) | 2022.10.02 |
[Design Pattern] Chapter 04 팩토리 패턴 (0) | 2022.10.01 |
[Design Pattern] Chapter 02 옵저버 패턴 (0) | 2022.09.25 |
[Design Pattern] Chapter 01 디자인 패턴 소개와 전략 패턴 (0) | 2022.09.25 |