자바 데코레이터 디자인 패턴 예제

데코레이터 디자인 패턴은 객체의 기능을 런타임에서 수정하는 데 사용됩니다. 동시에 동일한 클래스의 다른 인스턴스는 영향을받지 않으므로 개별 객체는 수정된 동작을 얻습니다. 데코레이터 디자인 패턴은 구조적 디자인 패턴 중 하나이며 (예: 어댑터 패턴, 브릿지 패턴, 컴포지트 패턴), 추상 클래스 또는 인터페이스를 구성하여 구현합니다.

데코레이터 디자인 패턴

우리는 상속 또는 구성을 사용하여 객체의 동작을 확장하지만 이는 컴파일 시에 이루어지며 해당 클래스의 모든 인스턴스에 적용됩니다. 실행 시에 새로운 기능을 추가하거나 기존 동작을 제거할 수는 없습니다. 이럴 때 데코레이터 패턴이 등장합니다. 우리가 다양한 종류의 자동차를 구현하고 싶다고 가정해봅시다. 우리는 assemble 메소드를 정의하는 Car 인터페이스를 만들 수 있고, 그런 다음 Basic car를 만들고, 이를 확장하여 Sports car와 Luxury Car를 만들 수 있습니다. 구현 계층 구조는 아래 이미지와 같습니다. 하지만 런타임에 스포츠 카와 럭셔리 카의 모든 기능을 가진 자동차를 얻고 싶다면, 구현이 복잡해집니다. 더 나아가 어떤 기능을 먼저 추가해야 하는지 지정하고 싶다면, 더욱 복잡해집니다. 이제 자동차의 종류가 10가지라고 상상해보세요. 상속과 구성을 사용한 구현 로직은 관리하기 불가능할 것입니다. 이러한 프로그래밍 상황을 해결하기 위해 자바에서는 데코레이터 패턴을 적용합니다. 데코레이터 디자인 패턴을 구현하기 위해 다음과 같은 유형이 필요합니다.

  1. 구성 요소 인터페이스 – 구현될 메서드를 정의하는 인터페이스 또는 추상 클래스입니다. 우리의 경우 Car가 구성 요소 인터페이스가 될 것입니다.

    package com.journaldev.design.decorator;
    
    public interface Car {
    
    	public void assemble();
    }
    
  2. 구성 요소 구현 – 구성 요소 인터페이스의 기본 구현입니다. BasicCar 클래스를 구성 요소 구현으로 사용할 수 있습니다.

    package com.journaldev.design.decorator;
    
    public class BasicCar implements Car {
    
    	@Override
    	public void assemble() {
    		System.out.print("Basic Car.");
    	}
    
    }
    
  3. 장식자 – 장식자 클래스는 구성 요소 인터페이스를 구현하며 구성 요소 인터페이스와 HAS-A 관계를 갖습니다. 구성 요소 변수는 하위 장식자 클래스에서 접근할 수 있어야 하므로 이 변수를 protected로 만듭니다.

    package com.journaldev.design.decorator;
    
    public class CarDecorator implements Car {
    
    	protected Car car;
    	
    	public CarDecorator(Car c){
    		this.car=c;
    	}
    	
    	@Override
    	public void assemble() {
    		this.car.assemble();
    	}
    
    }
    
  4. 구체적인 장식자 – 기본 장식자 기능을 확장하고 구성 요소 동작을 수정합니다. LuxuryCarSportsCar와 같은 구체적인 장식자 클래스를 가질 수 있습니다.

    package com.journaldev.design.decorator;
    
    public class SportsCar extends CarDecorator {
    
    	public SportsCar(Car c) {
    		super(c);
    	}
    
    	@Override
    	public void assemble(){
    		super.assemble();
    		System.out.print(" 스포츠 카의 기능 추가.");
    	}
    }
    
    package com.journaldev.design.decorator;
    
    public class LuxuryCar extends CarDecorator {
    
    	public LuxuryCar(Car c) {
    		super(c);
    	}
    	
    	@Override
    	public void assemble(){
    		super.assemble();
    		System.out.print(" 명품 자동차의 기능 추가.");
    	}
    }
    

데코레이터 디자인 패턴 – 클래스 다이어그램

데코레이터 디자인 패턴 테스트 프로그램

package com.journaldev.design.test;

import com.journaldev.design.decorator.BasicCar;
import com.journaldev.design.decorator.Car;
import com.journaldev.design.decorator.LuxuryCar;
import com.journaldev.design.decorator.SportsCar;

public class DecoratorPatternTest {

	public static void main(String[] args) {
		Car sportsCar = new SportsCar(new BasicCar());
		sportsCar.assemble();
		System.out.println("\n*****");
		
		Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
		sportsLuxuryCar.assemble();
	}

}

클라이언트 프로그램이 실행 중에 다양한 종류의 객체를 생성하고 실행 순서를 지정할 수 있다는 점에 유의하십시오. 위의 테스트 프로그램의 출력은 다음과 같습니다:

Basic Car. Adding features of Sports Car.
*****
Basic Car. Adding features of Luxury Car. Adding features of Sports Car.

데코레이터 디자인 패턴 – 중요한 포인트

  • 데코레이터 디자인 패턴은 실행 중에 수정 가능성을 제공하여 더 유연성을 제공합니다. 선택 사항이 많을 때 유지 및 확장하기 쉽습니다.
  • 데코레이터 디자인 패턴의 단점은 많은 유사한 종류의 객체(데코레이터)를 사용한다는 것입니다.
  • 데코레이터 패턴은 Java IO 클래스에서 많이 사용됩니다. 예를 들어 FileReader, BufferedReader 등이 있습니다.

Source:
https://www.digitalocean.com/community/tutorials/decorator-design-pattern-in-java-example