컴포지트 패턴이란?
- (여러 객체로 구성된 객체)복합 객체와 단일 객체를 클라이언트에서 구별 없이 다루게 해주는 패턴.
- 전체-부분의 관계(Directory-File)를 갖는 객체들 사이의 관계를 정의할 때 유용하다.
- 클라이언트는 전체와 부분을 구분하지 않고 동일한 인터페이스를 사용할 수 있다.
Leaf/ Composite 클래스 모두 공통의 인터페이스의 구현체이다.
Leaf: 부분 클래스, Composite 객체의 부품
Composite : 전체 클래스, 복수개의 Component를 갖는다. 심지어, 복수 개의 Leaf, 심지어 복수 개의 Composite 객체를 부분으로 가질 수 있다
패턴 적용 전
public class Computer {
private Keyboard Keyboard;
private Body body;
private Monitor monitor;
public addKeyboard(Keyboard keyboard) { this.keyboard = keyboard; }
public addBody(Body body) { this.body = body; }
public addMonitor(Monitor monitor) { this.monitor = monitor; }
public int getPrice() {
int keyboardPrice = keyboard.getPrice();
int bodyPrice = body.getPrice();
int monitorPrice = monitor.getPrice();
return keyboardPrice + bodyPrice + monitorPrice;
}
public int getPower() {
int keyboardPower = keyboard.getPower();
int bodyPower = body.getPower();
int monitorPower = monitor.getPower();
return keyboardPower + bodyPower + monitorPower;
}
}
새로운 부품(객체)를 추가하면, Computer 객체에 새로운 타입의(서로 다른 독립된 클래스이므로) 객체를 주입해야한다. 주입된 객체가 관여하는 비즈니스 로직도 메소드마다 업데이트 해줘야 한다. (위의 예제에서는, Computer의 getPrice()와 getPower()에 새 부품의 getPrice()와 getPower()가 추가될 것이다). OCP를 만족하지 않는다.
OCP란?
Open Close Principle(개방 패쇄의 원칙)
소프트웨어의 구성요소(컴포넌트, 클래스, 모듈, 함수)는 확장에 대해서는 개방(OPEN)되어야 하지만, 변경에 대해서는 폐쇠(CLOSE)되어야 한다는 의미이다.
즉, 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다는 의미이다.
패턴 적용 후
public class Keyboard extends ComputerDevice {
private int price;
private int power;
public Keyboard(int power, int price) {
this.power = power;
this.price = price;
}
public int getPrice() { return price; }
public int getPower() { return power; }
}
public class Body { 동일한 구조 }
public class Monitor { 동일한 구조 }
public class Computer extends ComputerDevice {
// 복수 개의 ComputerDevice 객체를 가리킴
private List<ComputerDevice> components = new ArrayList<ComputerDevice>();
// ComputerDevice 객체를 Computer 클래스에 추가
public addComponent(ComputerDevice component) { components.add(component); }
// ComputerDevice 객체를 Computer 클래스에서 제거
public removeComponent(ComputerDevice component) { components.remove(component); }
// 전체 가격을 포함하는 각 부품의 가격을 합산
public int getPrice() {
int price = 0;
for(ComputerDevice component : components) {
price += component.getPrice();
}
return price;
}
// 전체 소비 전력량을 포함하는 각 부품의 소비 전력량을 합산
public int getPower() {
int power = 0;
for(ComputerDevice component : components) {
price += component.getPower();
}
return power;
}
}
이제, Computer 클래스는 OCP를 준수한다. 부분 객체의 추가나 삭제 등이 있어도 전체 객체의 클래스 코드를 변경하지 않아도 된다.
즉, 전체-부분 관계를 갖는 객체들 사이의 관계를 정의할 때 유용하다.
컴포지트 패턴 구조
예시
폴더, 파일. 폴더에는 다양한 형식의 파일들이 있다. 또한 폴더 안에는 파일 뿐만 아니라 폴더 또한 담을 수 있다.
서로 다른 형식의 폴더 또는 파일들이 각각 독립된 클래스를 가져야 할까? 폴더 자신도 파일의 한 종류이다.
폴더, 파일 모두 하나의 인터페이스의 하위 클래스로 만들면, 폴더 안의 파일들이 형식이 달라도 인터페이스 리스트 형태로 관리할 수 있다. 따라서, 새 파일이 폴더에 추가 되더라도 폴더 클래스의 코드 변경 없이 OCP를 준수할 수 있다.
결론
이와 같이 트리 구조의 객체 구성이 요구될 때 적용되는 구조를 작 정의한 것이 컴퍼지트 패턴이다.
참고
https://gmlwjd9405.github.io/2018/08/10/composite-pattern.html
'Programming > 디자인 패턴' 카테고리의 다른 글
Template Method Pattern (0) | 2024.10.14 |
---|---|
데코레이터 패턴(Decorator Pattern) (0) | 2021.12.18 |
커맨드 패턴 (0) | 2021.12.12 |
프록시 패턴 (0) | 2021.12.11 |