책너두 (헤드 퍼스트 디자인 패턴) 9일차 (~139p)
- Book/헤드 퍼스트 디자인 패턴
- 2023. 7. 7.
요약
- 객체 꾸미기 (데코레이터 패턴) 계속
- Beverage 클래스 장식하기
- 커피 주문 시스템 코드 만들기
- 음료 코드 구현하기
- 첨가물 코드 구현하기
- 커피 주문 시스템 코드 테스트
- 데코레이터가 적용된 예 : 자바 I/O
- 자바 I/O 데코레이터 만들기
- 디자인 도구상자 안에 들어가야 할 도구들 추가
- OCP
- 데코레이터 패턴
메모
Beverage 클래스 장식하기
- CondimentDecorator (첨가물 데코레이터)는 꾸밀 대상인 Beverage 객체를 상속함.
- 상속을 통해, 데코레이터 객체가 자신이 감싸고 있는 객체랑 같은 형식을 맞춘다.
- 데코레이터가 꾸밀 대상을 구성으로 가지고 있기 때문에 행동(비용 계산)을 실행중에 동적으로 설정할 수 있음.
- 음료에 첨가물이 추가되도 유연성을 잃지 않음.
커피 주문 시스템 코드 만들기
- 더블 모카에 두유와 휘핑 크림을 추가한 음료를 만든다면?
public abstract class Beverage {
String description = "제목 없음";
public String getDescription() {
return description;
}
public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public abstract String getDescription();
}
- 첨가물은 음료 객체를 상속함.
- 데코레이터가 감쌀 음료 객체를 구성으로 가짐.
- 모든 음료 객체를 감쌀 수 있도록 음료 객체 슈퍼 클래스를 가짐
음료 코드 구현하기
public class Espresso extends Beverage {
public Espresso() {
description = "에스프레소";
}
public double cost() {
return 1.99;
}
}
- 실제 음료인 에스프레소는 description 변수를 설정함.
- 에스프레소 가격을 계산함.
- 첨가물 가격을 걱정할 필요가 없음.
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "하우스 블렌드 커피";
}
public double cost() {
return .89;
}
}
- 에스프레소와 거의 동일함.
첨가물 코드 구현하기
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", 모카";
}
public double cost() {
return beverage.cost() + .20;
}
}
- 첨가물 구상체는 인스턴스 변수로 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());
}
}
- 감쌀 대상인 Beverage 를 먼저 선언하고, 이를 첨가물 생성자를 통해 계속 감싸주기만 하면 됨.
데코레이터가 적용된 예 : 자바 I/O
- FileInputStream 은 데코레이터로 장식할 예정인 구상 객체임. → 추상 구성 요소는 InputStream.
- BufferedInputStream은 구상 데코레이터로, FileInputStream에 입력을 미리 읽어서 더 빠르게 처리할 수 있게 해주는 버퍼링 기능을 더해 주는 역할임
- ZipInputStream도 구상 데코레이터 → zip 파일에서 데이터를 읽어 올 때, 그 속에 있는 항목을 읽는 기능임.
- 추상 데코레이터는 FilterInputStream.
- 출력 스트림 디자인도 똑같음.
- 이러한 데코레이터 패턴은, 잡다한 클래스가 너무 많아짐.
- 데코레이터 패턴이 적용된 API를 사용하는 개발자는 괴로움.
- 하지만, 데코레이터 패턴이 어떤 식으로 작동하는지 이해하면, 데코레이터 패턴으로 감싸서 원하는 행동을 구현할 수 있음.
자바 I/O 데코레이터 만들기
- 입력 스트림에 있는 대문자를 전부 소문자로 바꿔주는 데코레이터를 만든다면?
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = in.read();
return (c == -1 ? c Character.toLowerCase((char)c));
}
public int read(byte[] b, int offset, int len) throws IOException {
int result = in.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte) Character.toLowerCase((char)b[i]);
}
return result;
}
}
public class InputTest {
public static void main(String[] args) throws IOException {
int c;
try {
InputStream in =
new LowerCaseInputStream(
new BufferedInputStream(
new FileInputStream("test.txt")));
while((c = in.read()) >= 0) {
System.out.print((char)c);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 이런식으로 데코레이터를 감싸서 InputStream을 사용할 수 있음.
디자인 도구상자 안에 들어가야 할 도구들
- 데코레이터 패턴과 OCP가 추가됨.
'Book > 헤드 퍼스트 디자인 패턴' 카테고리의 다른 글
책너두 (헤드 퍼스트 디자인 패턴) 11일차 (~165p) (0) | 2023.07.10 |
---|---|
책너두 (헤드 퍼스트 디자인 패턴) 10일차 (~152p) (0) | 2023.07.08 |
책너두 (헤드 퍼스트 디자인 패턴) 8일차 (~125p) (0) | 2023.07.06 |
책너두 (헤드 퍼스트 디자인 패턴) 7일차 (~113p) (0) | 2023.07.05 |
책너두 (헤드 퍼스트 디자인 패턴) 6일차 (~101p) (0) | 2023.07.03 |