# 설명
Composite은 "합성물"이라는 뜻을 가지고 있다. 예측이 불가능한 이 이름을 먼저 위키백과에 검색해보자
컴포지트 패턴(Composite Pattern)이란 객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴으로, 사용자가 단일 객체와 복합 객체 모두 동리하게 다루도록 한다.
트리구조는 쉽게 이해된다. 그렇다면 부분-전쳬계층을 뜻하는 단일 객체와 복합객체는 무슨 의미를 가지고 있는 것일까? 이를 흔히들 파일과 폴더의 구조로 설명을 한다고 한다. 폴더안에는 여러 파일이 들어갈 수 있을 뿐만 아니라 폴더를 가지고 있을 수도 있다. 그러나 파일안에 폴더는 들어가지 못한다. 단일객체가 파일, 복합객체가 폴더의 의미로 연결지어 보면 쉬울 것이다. 이를 통해 부분과 전체에 대한 복합 객체의 트리구조를 표현 할 수 있다.
그러기 위해선 클라이언트가 개별 객체와 복합 객체를 동일하게 다룰 수 있는 무언가(인터페이스,추상클래스)가 필요하다. 이를 Component로 정의하여, 전체와 부분 객체에서 공통적으로 사용할 인터페이스를 선언한다. 또한 전체와 부분 객체에서 공통을 사용할 기능을 구현하고, 부분요소들을 관리하기 위한 인터페이스를 선언한다.
- Leaf는 다른 객체를 포함할 수는 없고 포함되기만 하는 객체로 가장 기본이 되는 기능을 구현한다.
- Composite는 복합객체에 대한 기능을 구현한다. 포함될 여러 객체를 저장하고 관리하는 기능이 필요할 것이다.
이렇게 설계함으로써 Clinet에서는 개별객체와 복합객체를 동일하게 다룰 수 있다.
# 예제 설명
이번 예제에서, Category와 Product를 통해서 컴포지트패턴을 사용해 볼 수 있다. Product-Category는 컴포넌트 역할을 해서, 공통사항을 구현하고, Leaf와 Composite에서 구현해야할 사항들을 추상메소드로 남긴다.
Product에서는 복합객체를 관리하는 행위에 대해서 정의할 필요가 없을 것이다. Category에서는 복합객체에 관리에 대한 정의를 구현해준다.
이를 통해, 위와 같은 트리구조를 만들 수 있다. 카테고리에 접근하여 필요한 기능(추가,삭제 등등)을 사용할 수 있다.
# 코드
## ProductCategory - Component
공통의 기능은 여기서 구현해준다.
// ProductCategory
public abstract class ProductCategory {
public int id;
public String name;
public int price;
public ProductCategory(int id, String name, int price){
this.id = id;
this.name = name;
this.price = price;
}
public abstract void addProduct(ProductCategory product);
public abstract void removeProduct(ProductCategory product);
public abstract int getCount();
public abstract String getName();
public abstract int getPrice();
public abstract int getId();
}
## Category - Composite
복합객체로써, 다른 요소들을 관리하고 저장할수 있어야 한다.
// Category
public class Category extends ProductCategory {
ArrayList<ProductCategory> list;
public Category(int id, String name, int price) {
super(id, name, price);
list = new ArrayList<ProductCategory>();
}
@Override
public void addProduct(ProductCategory product) {
list.add(product);
}
@Override
public void removeProduct(ProductCategory product) {
for (ProductCategory item : list) {
if (item.getId() == product.id) {
System.out.println(product.getName() + "을 삭제합니다");
list.remove(product);
return;
}
}
System.out.println("일치하는 카테고리가 없어 삭제할 수 없습니다.");
}
@Override
public int getCount() {
int totalCount = 0;
for (ProductCategory item : list) {
totalCount += item.getCount();
}
return totalCount;
}
@Override
public String getName() {
return name;
}
@Override
public int getPrice() {
int totalPrice = 0;
for (ProductCategory item : list) {
totalPrice += item.getPrice();
}
return totalPrice;
}
@Override
public int getId() {return id;}
}
## Product - Leaf
// Product
public class Product extends ProductCategory {
public Product(int id, String name, int price){
super(id,name,price);
}
@Override
public void addProduct(ProductCategory product) {}
@Override
public void removeProduct(ProductCategory product) {}
@Override
public int getCount() {
return 1;
}
@Override
public String getName(){return name;}
@Override
public int getPrice() {return price;}
@Override
public int getId() {return id;}
}
# 테스트
public class Test {
public static void main(String[] args) {
ProductCategory Vehicle = new Category(0,"Vehicle-Category",0);
ProductCategory CarCategory = new Category(1,"Car-Category",0);
ProductCategory MotorBikeCategory = new Category(2,"MotorBike-Category",0);
// 탈것에 자동차와 오토바이 카테고리를 추가함
Vehicle.addProduct(CarCategory);
Vehicle.addProduct(MotorBikeCategory);
ProductCategory Ferrari = new Product(100,"Ferrari488",1000);
ProductCategory Porsche = new Product(200,"Porsche918-Boxter",1000);
ProductCategory Sonata = new Product(300,"Sonata-Trubo",300);
CarCategory.addProduct(Ferrari);
CarCategory.addProduct(Porsche);
CarCategory.addProduct(Sonata);
ProductCategory SuperCurve = new Product(10,"SuperCurve", 10);
ProductCategory R6 = new Product(20,"R6", 100);
MotorBikeCategory.addProduct(SuperCurve);
MotorBikeCategory.addProduct(R6);
System.out.println("Vehicle에 속한 총 항목의 갯수 : " + Vehicle.getCount() + ", 총 가격 " + Vehicle.getPrice());
System.out.println("CarCategory에 속한 총 항목의 갯수 : " + CarCategory.getCount() + ", 총 가격 " + CarCategory.getPrice());
System.out.println("MotorBikeCategory 속한 총 항목의 갯수 : " + MotorBikeCategory.getCount() + ", 총 가격 " + MotorBikeCategory.getPrice());
// 삭제
MotorBikeCategory.removeProduct(SuperCurve);
System.out.println("MotorBikeCategory 속한 총 항목의 갯수 : " + MotorBikeCategory.getCount() + ", 총 가격 " + MotorBikeCategory.getPrice());
System.out.println("Vehicle에 속한 총 항목의 갯수 : " + Vehicle.getCount() + ", 총 가격 " + Vehicle.getPrice());
}
}
'• 독서 > Design Pattern' 카테고리의 다른 글
[디자인 패턴] 스테이트 패턴(State Pattern) (0) | 2022.10.02 |
---|---|
[디자인패턴] 어댑터 패턴(Adapter Pattern) (0) | 2022.10.01 |
[디자인패턴] 데코레이터 패턴(Decorator Pattern) (0) | 2022.09.27 |
[디자인패턴] 브릿지 패턴(Bridge Pattern) (0) | 2022.09.22 |
[디자인패턴] 전략패턴 (Strategy Pattern) (1) | 2022.09.21 |