상세 컨텐츠

본문 제목

[Design Pattern] Composite Pattern

JAVA

by jeonghojin 2023. 3. 28. 00:36

본문

Composite Pattern

클라이언트가 복합 객체나 단일 객체를 동일하게 취급하는 것을 목적으로 한다.
 
객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴으로, 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 하는 패턴이다.
 

 

Component : 모든 component 들을 위한 추상화된 개념으로써, Leaf와 Composite 클래스의 인터페이스이다.
Leaf : Component 인터페이스를 구현한 클래스
Composite :
- 내부에 다른 클래스 요소를 포함하고 있는 요소(Leaf 를 포함하고 있는 요소)
- Component 인터페이스를 구현하고, 구현되는 자식(Leaf or Composite)들을 가진다.
- 이러한 자식들을 관리하기 위한 메서드(addChild, removeChild...)를 구현
- 일반적으로 인터페이스에 작성된 메서드는 자식에게 위임하는 처리를 한다.
Client : Component를 통해 외부에서 메세지를 요청하는 객체

- Client는 Leaf, Composite를 직접 참조하지 않고, 공통 인터페이스인 Component를 참조한다.
 

구조 패턴 :
구조패턴은 작은 클래스들을 상속과 합성을 이용해 더 큰 클래스를 생성하는 방법을 제공하는 패턴이다.

구조패턴을 사용하면 독립적으로 개발한 클래스 라이브러리를 하나로 사용할 수 있는 장점이 있따. 또 여러 인터페이스를 합성하여 서로 다른 인터페이스들의 통일된 추상을 제공한다.

구조패턴의 중요한 포인트는 인터페이스나 구현을 복합하는 것이 아닌, 객체를 합성하는 방법을 제공하는 것이다.

 

 
Client 에서 Top-Level 에 존재하는 Composite1에 요청을 보낸다. Component 인터페이스를 구현한 객체들은 트리구조를 토대로 위에서 아래 방향으로 모든 자식 요소에게 전달하게 된다.
 


복합 객체와 단일 객체의 처리 방법이 다르지 않을 경우, 전체-부분 관계로 정의할 수 있다.
* ex ) directory
- 전체-부분 관계를 트리 구조로 표현하고 싶은 경우.
- 전체-부분 관계를 클라이언트에서 부분, 관계 객체를 균일하게 처리하고 싶을 경우.


예제 : FileSystem
 
interface FileSystem

public interface FileSystem {
    int getSize();
    void remove();
}

class File

public class File implements FileSystem {

    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public int getSize() {
        System.out.println(name + " 파일 크기 : "+size);
        return size;
    }

    @Override
    public void remove() {
        System.out.println(name + " 파일 삭제");
    }
}

class Folder

import java.util.ArrayList;

public class Folder implements FileSystem {

    private String name;
    private ArrayList<FileSystem> files = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    public void add(FileSystem fileSystem) {
        files.add(fileSystem);
    }

    @Override
    public int getSize() {
        int total = 0;
        for (FileSystem file : files) {
            total += file.getSize();
        }

        System.out.println(name + " 폴더 크기 : "+total);
        System.out.println("---------------------");
        return total;
    }

    @Override
    public void remove() {
        for (int i = 0; i < files.size(); i++) {
            files.get(i).remove();
            files.remove(i);
        }

        System.out.println(name + " 폴더 삭제");
        System.out.println("---------------------");

    }
}

 
Main

public class Main {
    public static void main(String[] args) {

        Folder parentFolder = new Folder("최상위 폴더");

        Folder parentFolder1 = new Folder("상위 폴더1");
        Folder parentFolder2 = new Folder("상위 폴더2");

        parentFolder.add(parentFolder1);
        parentFolder.add(parentFolder2);

        File file11 = new File("파일1-1", 256);
        parentFolder1.add(file11);

        File file21 = new File("파일2-1", 256);
        File file22 = new File("파일2-2", 256);

        parentFolder2.add(file21);
        parentFolder2.add(file22);

        parentFolder1.getSize();
        parentFolder2.getSize();
        parentFolder.getSize();

        parentFolder1.remove();
        parentFolder1.getSize();
        parentFolder.getSize();
    }
}

예제 2

public class Keyboard {

    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 {...} // 위와 동일 구조
import java.security.Key;

public class Computer {
    private Keyboard keyboard;
    private Body body;
    private Monitor monitor;

    public void  addKeyboard(Keyboard keyboard) {this.keyboard = keyboard;}
    public void  addBody(Body body) {this.body = body;}
    public void  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;
    }


}
import java.security.Key;

public class Main {
    public static void main(String[] args) {

        Keyboard keyboard = new Keyboard(5, 2);
        Body body = new Body(100, 70);
        Monitor monitor = new Monitor(20, 30);

        Computer computer = new Computer();
        computer.addKeyboard(keyboard);
        computer.addBody(body);
        computer.addMonitor(monitor);

        int computerPrice = computer.getPrice();
        int computerPower = computer.getPower();

        System.out.println("Computer Price : "+computerPrice + "만원");
        System.out.println("Computer Power : "+computerPower + "W");

    }
}

 

* 위 코드는 새로운 부품들이 추가될 때마다 코드의 변경이 발생하게 된다. 즉,

OCP 를 만족하지 않는다.

 

구체적인 부품들을 일반화할 수 있는 클래스를 정의하고 이를 Computer 클래스가 가리키도록 설계한다.

 


public abstract class AbstractComponent{
    public abstract int getPrice();
    public abstract int getPower();
}
public class Body extends AbstractComponent {

    private int power;
    private int price;

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


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

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

public class Keyboard extends AbstractComponent {...} // 위와 동일
public class Monitor extends AbstractComponent {...} // 위와 동일
import java.util.ArrayList;
import java.util.List;

public class Computer extends AbstractComponent {

    private List<AbstractComponent> components = new ArrayList<>();

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

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

    public int getPrice() {
        int price = 0;
        for (AbstractComponent component : components) {
            price += component.getPrice();
        }
        return price;
    }

    public int getPower() {
        int power = 0;
        for (AbstractComponent component : components) {
            power += component.getPower();
        }
        return power;
    }
}

 

public class Main {
    public static void main(String[] args) {

        AbstractComponent keyboard = new Keyboard(5, 2);
        AbstractComponent body = new Keyboard(3, 1);
        AbstractComponent monitor = new Keyboard(30, 20);

        Computer computer = new Computer();
        computer.addComponent(keyboard);
        computer.addComponent(body);
        computer.addComponent(monitor);

        System.out.println("power : "+computer.getPower());
        System.out.println("price : "+computer.getPrice());
        computer.removeComponent(body);

        System.out.println("power : "+computer.getPower());
        System.out.println("price : "+computer.getPrice());
    }
}

Composite Pattern 장/단점

장점 :
- 객체들이 모두 같은 타입으로 취급되기 때문에 새로운 클래스 추가가 용이하다.
- 단일 객체, 집합 객체 구분하지 않고 코드 작성이 가능하다.
 
단점 : 
- 설계를 일반화시켜 객체 간의 구분, 제약이 힘들다.
 


참고 :

더보기

https://mygumi.tistory.com/343

컴포지트 패턴(Composite Pattern) :: 마이구미

이 글은 디자인 패턴 중 컴포지트 패턴(Composite Pattern) 을 다룬다.위키피디아의 내용을 기반으로 정리할 예정이다.위키 - https://en.wikipedia.org/wiki/Composite_pattern 글의 주제를 다루기에 앞서, 글들을

mygumi.tistory.com

https://jdm.kr/blog/228

컴포지트 패턴(Composite Pattern) :: JDM's Blog

개요 컴포지트 패턴Composite Pattern은 간단하게 말해 단일 객체Single Instance든 객체들의 집합Group of Instance이든 같은 방법으로 취급하는 것입니다. 다시 말해, 개별적인 객체들과 객체들의 집합간의

jdm.kr

https://johngrib.github.io/wiki/pattern/composite/

컴포짓 패턴 (Composite Pattern)

개별 객체와 복합 객체를 모두 동일하게 다룰 수 있도록 한다.

johngrib.github.io

https://magpienote.tistory.com/138

[JAVA]객체 지향 디자인 패턴 - Composite Pattern(컴포지트 패턴)

Composite Pattern이란? Composite는 '합성물', '혼합', '혼성' 등 이라는 뜻을 가지고 있음 합성한 객체들의 집합이라는 개념으로 이해하면 됨 컴포지트 패턴은 트리구조를 작성하고 싶을 때 사용하며,

magpienote.tistory.com

https://i5i5.tistory.com/689

[디자인패턴] Composite패턴(컴포지트패턴)이란?

디자인패턴의 종류 https://i5i5.tistory.com/537 [CS] GoF 디자인패턴의 종류. (Design Pattern) 이번 글은, GoF 디자인패턴의 종류들에 대해서 알아보겠습니다. 디자인패턴은 소프트웨어를 설계할 때, 역사적

i5i5.tistory.com

https://dailyheumsi.tistory.com/193

[디자인 패턴 7편] 구조 패턴, 컴퍼지트(Composite)

1. 개념 컴퍼지트 패턴은 단일 객체와 그 객체들을 가지는 집합 객체를 같은 타입으로 취급하며, 트리 구조로 객체들을 엮는 패턴이다. 1.1. 장점 객체들이 모두 같은 타입으로 취급되기 때문에

dailyheumsi.tistory.com

https://gmlwjd9405.github.io/2018/08/10/composite-pattern.html

[Design Pattern] 컴퍼지트 패턴이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

'JAVA' 카테고리의 다른 글

[Design Pattern] Proxy Pattern  (0) 2023.03.29
[Design Pattern] Adapter Pattern  (0) 2023.03.28
[Design Pattern] State Pattern  (0) 2023.03.26
[Design Pattern] Builder Pattern  (0) 2023.03.25
[Design Pattern] Decorator Pattern  (0) 2023.03.24

관련글 더보기