Composite

GamSa Ham·2022년 10월 15일
0

GoF디자인패턴

목록 보기
6/22
post-thumbnail

복합체

의도 : 부분과 전체의 계층을 표현하기 위해 객체들을 모아 트리 구조로 구성함 개별 객체와 복합 객체를 모두 동일하게 다룰 수 있도록 하는 패턴
부분 - 전체의 객체 계통을 표현하고 싶거나 사용자가 객체의 합성으로 생긴 복합 객체와 개별 객체 사이의 차이를 알지 않고도 자기 일을 할 수 있도록 만들고 싶을 때 사용함 사용자는 복합 구조의 모든 객체를 똑같이 취급하게 됨

구조 :

참여자 :

  1. Component - 집합 관계에 정의될 모든 객체에 대한 인터페이스를 정의함 모든 클래스에 해당하는 인터페이스에 대해 공통의 행동을 구현하며 전체 클래스에 속한 요소들을 관리하는 데에 필요한 인터페이스 정의
  2. Leaf - 가장 말단의 객체, 자식이 없는 객체로 객체 합성에 가장 기본이 되는 객체의 행동 정의 (오브젝트)
  3. Composite - 자식이 있는 구성요소에 대한 행동을 정의함 자신이 복합하는 요소들을 저장하며 Component 인터페이스에 정의된 자식 관련 연산 구현 (오브젝트 그룹)
  4. Client - Component 인터페이스를 통해 복합 구조 내의 객체들을 조작함

협력 방법 : 사용자는 복합 구조 내 객체 간의 상호작용을 위해 Component 클래스 인터페이스를 사용하며 요청받은 대상이 Leaf 인스턴스이면 자신이 정의한 행동을 직접 수행하고 대상이 Composite이면 자식 객체들에게 요청을 위임함

예제 :

public abstract class Component {
	
	private String name;
	
	public Component(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}

}
public class Folder extends Component{

	List<Component> children = new LinkedList<>();
	
	public Folder(String name) {
		super(name);
	}
	
	public List<Component> getChildren() {
		return children;
	}
	
	public void addComponent(Component component) {
		children.add(component);
	}
	
	public void removeComponent(Component component) {
		children.remove(component);
	}
	
}
public class File extends Component {

	private Object data;
	
	public File(String name) {
		super(name);
	}
	
	public Object getData() {
		return data;
	}
	
	public void setData(Object data) {
		this.data = data;
	}

}
public class Main {
	
	public static void main(String[] args) {
	
		Folder
		root = new Folder("root"),
		download = new Folder("download"),
		document = new Folder("document"),
		picture = new Folder("picture"),
		music = new Folder("music");
	
		File
		down1 = new File("down1"),
		down2 = new File("down2"),
		pic1 = new File("pic1"),
		pic2 = new File("pic2"),
		music1 = new File("music1"),
		music2 = new File("music2");
	
		root.addComponent(download);
		root.addComponent(document);
	
		document.addComponent(picture);
		document.addComponent(music);
	
		download.addComponent(down1);
		download.addComponent(down2);
	
		picture.addComponent(pic1);
		picture.addComponent(pic2);
	
		music.addComponent(music1);
		music.addComponent(music2);
	
		show(root);
	
	}
	
	private static void show(Component component) {
		System.out.println(component.getClass().getName() + "|" + component.getName());
		if (component instanceof Folder) {
			for (Component c : ((Folder)component).getChildren()) {
				show(c);
			}
		}
	}

}

투명성 : 자식을 관리하는 인터페이스를 최상위에 위치 시킬 경우 서브클래스 모두에게 동일한 인터페이스가 적용되므로 투명성을 보장함 하지만 사용자가 Leaf 클래스의 인스턴스에 Add()나 Remove() 연산을 호출하는 불필요한 경우가 없도록 하는 데에 비용 소모

안전성 : Composite 클래스에서 자식을 관리하는 연산을 정의하면 Leaf 클래스에서는 이러한 연산을 호출할 수 없으므로 안전성을 보장 받지만 Leaf 클래스와 Composite 클래스가 다른 인터페이스를 갖게 되므로 사용자는 이를 동일한 대상으로 간주하고 사용할 수 없음

Case :

  1. (투명성을 우선시하여) getComposite() 연산을 통해 해당 객체가 Composite인지 아닌지 판단하여 해당되는 경우에만 Add() Remove() 요청할 수 있도록 함
    => 모든 구성요소를 동일한 방식으로 처리하지 않을 경우
  2. 연산 호출 시 연산을 처리할 수 있는 대상인지 일일이 검사
    => 확장성에 바람직하지 않음
  3. Add()의 구성요소가 자식을 가질 수 있는가? (!= Leaf)
    Remove()의 인자가 구성요소의 자식인가?
    해당하지 않을 경우 실패 또는 예외 처리

사용예 : Smalltalk의 모델/뷰/컨트롤러에서 View 클래스는 서브뷰 집합을 포함하고 있어 Component 클래스이자 Composite 클래스이기도 함

profile
안녕하세요. 자바를 좋아하고 디자인 패턴, Refactoring, Clean Code에 관심이 많은 백엔드 개발자입니다.

0개의 댓글