Decorator Pattern

2023. 10. 21. 15:50디자인패턴

728x90

문제 배경

여러음료를 만들려고 한다
음료마다 가격이 다르고 들어가는 재료가 다르다
새로운 음료가 생길때마다 상위클래스를 계속 수정해야 하는 문제가 생긴다.
 
 
Open-Closed Principle(OCP)
: 중요한 디자인 원칙
클래스는 확장(새로운 기능 추가)에 대해서는 개방적이고, 수정에 대해서는 폐쇄적이다.
-> 기존의 코드를 수정하지 않고 새로운 기능을 추가할 수 있도록 해야한다.
 
 

Decorator Pattern

: 개체에 동적으로 추가적인 책임을 부여하도록 설계
 
1. DarkRoast 객체가 있다고 가정.
그때의 가격을 포함
2. 모카를 추가한다면 Mocha 객체로 DarkRoast객체를 감싼다.
모카를 추가한 가격을 포함
3.휘핑을 추가한다면 Whip 객체로 Mocha객체를 감싼다.
휘핑을 추가한 가격을 포함.

 
 

Framework

 
 
 
 

Code

public abstract class Beverage { 
//음료에 따라 출력값이 계속 바뀔거기 때문에 추상클래스로 Beverage 생성
    String description = “Unknown Beverage”;
    public String getDescription() {
        return description;
    }
    public abstract double cost(); //가격도 계속 바뀔거기 때문에 추상메소드로 생성
}

public abstract class CondimentDecorator extends Beverage { 
//음료를 변경할 수 있도록 자식클래스 생성
	public abstract String getDescription();
}
public class Espresso extends Beverage { //에스프레소
    public Espresso() {
    	description = “Espresso”;
    }
    public double cost() {
    	return 1.99;
    }
}

public class HouseBlend extends Beverage { //하우스블랜드
    public HouseBlend() {
    	description = “House Blend Coffee”;
    }
    public double cost() {
    	return .89;
    }
}
public class Mocha extends CondimentDecorator { //음료에 모카를 추가
    Beverage beverage; //Has-A 관계
    public Mocha(Beverage beverage) {
    	this.beverage = beverage;
    }
    public String getDescription() {
    	return beverage.getDescription() + “, Mocha”;
    }
    public double cost() {
    	return .20 + beverage.cost();
    }
}
public class StarbuzzCoffee {
    public static void main(String args[]) {
        Beverage beverage = new Espresso(); //에스프레소 생성
        System.out.println(beverage.getDescription()
        + “ $” + beverage.cost());
        
        Beverage beverage2 = new DarkRoast(); //다크로스트 생성
        //모카 2번과 휘핑크림1번 추가
        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());
    }
}

 
 

자바에서 Decorator Pattern 사용예시

: Java I/O

 

 
Java I/O를 Decorator Pattern으로 새로운 함수 만들기

public class LowerCaseInputStream extends FilterInputStream { //문자를 소문자로 변형하는 클래스
    public LowerCaseInputStream(InputStream in) { //생성자
    	super(in);
    }
    public int read() throws IOException {
        int c = super.read();
        return (c == -1 ? c : Character.toLowerCase((char)c));
    }
    public int read(byte[] b, int offset, int len) throws IOException {
        int result = super.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”))); //decorate 
        while((c = in.read()) >= 0) {
        	System.out.print((char)c);
        }
        in.close();
        } catch (IOException e) {
        	e.printStackTrace();
        }
    }
}
728x90

'디자인패턴' 카테고리의 다른 글

The Adapter and Facade Patterns  (0) 2023.10.21
The Command Pattern  (1) 2023.10.21
The Singleton Pattern  (1) 2023.10.21
The observer pattern  (0) 2023.10.19
Strategy Pattern  (0) 2023.10.18