티스토리 뷰

728x90
반응형

컴포지트 패턴


  • 여러개의 객체들로 구성된 복합 객체와 단일 객체를 클라이언트에서 구별없이 다루게 해주는 패턴입니다.
  • 클라이언트는 복합 객체와 단일 객체를 신경쓰지 않고 인터페이스를 통해 어떠한 객체든 사용할 수 있습니다.

 

 

클래스 다이어 그램


 

Component
  • Leaf 클래스와 Composite 클래스의 공통 인터페이스 정의
Leaf
  • 구체적인 부분 클래스
  • Composite 객체의 부품으로 설정
Composite
  • 전체 클래스
  • 복수개의 Component를 갖도록 정의

 

 

예시


휴대폰에 각종 기능 장착하기

// 배터리 기능
@Getter
public class Battery {
    private int price;
    private int power;

    public Battery(int price, int power) {
        this.price = price;
        this.power = power;
    }
}

// 저장 용량 기능
@Getter
public class StorageCapacity {
    private int price;
    private int power;

    public StorageCapacity(int price, int power) {
        this.price = price;
        this.power = power;
    }
}

// 플래쉬 기능
@Getter
public class Flash {
    private int price;
    private int power;

    public Flash(int price, int power) {
        this.price = price;
        this.power = power;
    }
}
public class SmartPhone {
    private Battery battery;
    private StorageCapacity storageCapacity;
    private Flash flash;

    public void addBattery(Battery battery) {
        this.battery = battery;
    }

    public void addStorageCapacity(StorageCapacity storageCapacity) {
        this.storageCapacity = storageCapacity;
    }

    public void addFlash(Flash flash) {
        this.flash = flash;
    }

     public int getPrice(){
        return battery.getPrice() + storageCapacity.getPrice() + flash.getPrice();
    }

    public int getPower() {
        return battery.getPower() + storageCapacity.getPower() + flash.getPower();
    }
}
public class Client {
    public static void main(String[] args) {
        Battery battery = new Battery(100000, 50);
        StorageCapacity storageCapacity = new StorageCapacity(150000, 60);
        Flash flash = new Flash(200000, 80);

        SmartPhone smartPhone = new SmartPhone();
        smartPhone.addBattery(battery);
        smartPhone.addStorageCapacity(storageCapacity);
        smartPhone.addFlash(flash);

        int smartPhonePrice = smartPhone.getPrice();
        int smartPhonePower = smartPhone.getPower();

        System.out.println("SmartPhone Price = " + smartPhonePrice + "원");
        // SmartPhone Price = 450000원
        System.out.println("SmartPhone Power = " + smartPhonePower + "W");
        // SmartPhone Power = 190W
    }
}

 

 

상황 : 여기서 다른 부품이 추가되어야한다면?
  • 현재 위와 같은 구조로 카메라와 스피커의 기능이 추가된다면 어떻게 될까?

// 추가되는 기능
@Getter
public class Camera {
    private int price;
    private int power;

    public Camera(int price, int power) {
        this.price = price;
        this.power = power;
    }
}

// 추가되는 기능
@Getter
public class Speaker {
    private int price;
    private int power;

    public Speaker(int price, int power) {
        this.price = price;
        this.power = power;
    }
}
public class SmartPhone {
    ...

    /**
     * 추가되는 기능
     */
    private Camera camera;
    private Speaker speaker;

    ...

    /**
     * 추가되는 기능
     */
    public void addCamera(Camera camera) {
        this.camera = camera;
    }

    public void addSpeaker(Speaker speaker) {
        this.speaker = speaker;
    }

     public int getPrice(){
        return battery.getPrice() +
               storageCapacity.getPrice() +
               flash.getPrice() +
               camera.getPrice() +
               speaker.getPrice();
    }

    public int getPower() {
        return battery.getPower() +
               storageCapacity.getPower() +
               flash.getPower() +
               camera.getPower() +
               speaker.getPower();
    }
}
public class Client {
    public static void main(String[] args) {
        Battery battery = new Battery(100000, 50);
        StorageCapacity storageCapacity = new StorageCapacity(150000, 60);
        Flash flash = new Flash(200000, 80);
        Camera camera = new Camera(300000, 80);
        Speaker speaker = new Speaker(500000, 80);

        SmartPhone smartPhone = new SmartPhone();
        smartPhone.addBattery(battery);
        smartPhone.addStorageCapacity(storageCapacity);
        smartPhone.addFlash(flash);
        smartPhone.addCamera(camera);
        smartPhone.addSpeaker(speaker);

        int smartPhonePrice = smartPhone.getPrice();
        int smartPhonePower = smartPhone.getPower();

        System.out.println("SmartPhone Price = " + smartPhonePrice + "원");
        // SmartPhone Price = 1250000원
        System.out.println("SmartPhone Power = " + smartPhonePower + "W");
        // SmartPhone Power = 350W
    }
}

 

문제점
  • 위 상황의 문제점은 새로운 부품이 추가될 때 마다 SmartPhone 클래스를 계속하여 수정을 해야합니다.
  • SmartPhone 클래스에 속한 여러 구체적인 객체들을 가리키게되면 OCP원칙을 위반하게 됩니다.

 

해결책
  • 구체적인 부품들을 일반화한 클래스를 정의하고 이를 SmartPhone 클래스가 가리키도록합니다.

 

Component의 역할을 하는 클래스
public interface SmartPhoneDevice {
     int getPrice();
     int getPower();
}

 

Leaf의 역할을 하는 클래스
// 배터리 기능
public class Battery implements SmartPhoneDevice {
    private int price;
    private int power;

    public Battery(int price, int power) {
        this.price = price;
        this.power = power;
    }

    @Override
    public int getPrice() {
        return this.price;
    }

    @Override
    public int getPower() {
        return this.power;
    }
}

... Camera, Flash, Speaker, StorageCapacity의 역할을 하는 기능 동일

 

Composite의 역할을 하는 클래스
public class SmartPhone implements SmartPhoneDevice{
    private List<SmartPhoneDevice> components = new ArrayList<>();

    public void addComponent(SmartPhoneDevice component) {
        components.add(component);
    }

    public void removeComponent(SmartPhoneDevice component) {
        components.remove(component);
    }

    @Override
    public int getPrice() {
        return components.stream().mapToInt(SmartPhoneDevice::getPrice).sum();
    }

    @Override
    public int getPower() {
        return components.stream().mapToInt(SmartPhoneDevice::getPower).sum();
    }
}

 

Client
public class Client {
    public static void main(String[] args) {
        SmartPhoneDevice battery = new Battery(100000, 50);
        SmartPhoneDevice storageCapacity = new StorageCapacity(150000, 60);
        SmartPhoneDevice flash = new Flash(200000, 80);
        SmartPhoneDevice camera = new Camera(300000, 80);
        SmartPhoneDevice speaker = new Speaker(500000, 80);

        SmartPhone smartPhone = new SmartPhone();
        smartPhone.addComponent(battery);
        smartPhone.addComponent(storageCapacity);
        smartPhone.addComponent(flash);
        smartPhone.addComponent(camera);
        smartPhone.addComponent(speaker);

        int smartPhonePrice = smartPhone.getPrice();
        int smartPhonePower = smartPhone.getPower();

        System.out.println("SmartPhone Price = " + smartPhonePrice + "원");
        // SmartPhone Price = 1250000원
        System.out.println("SmartPhone Power = " + smartPhonePower + "W");
        // SmartPhone Power = 350W
    }
}

 

728x90
반응형