open:composite-pattern

Composite Pattern

여배우인 벨라 호크(Bella Hock)가 소셜 네트워크에서 사용자 아바타를 보지 못하고 있다.

“모든 것이 검은 색이예요. 이거 블랙홀인가요?”

페드로: 이거 검정 사각형이네요.

이브: 흠, 이쪽도 같은 문제가 있어요.

페드로: 마지막에 추가된 기능이 사용자 아바타에 버그를 만든 것 같네요.

이브: 이상하네요, 아바타는 다른 요소들과 같은 방식으로 랜더링해요. 하지만 아바타는 눈에 보이는 거죠.

페드로: 같은 방식으로 랜더링하는 거 확실해요?

이브: 글쎄요…​ 아니요.

코드를 파 본다.

페드로: 도대체 이 코드들이 뭘 하는 거죠?

이브: 누군가 복사해서 붙여넣기를 했네요. 하지만 아바타에 변경 사항을 반영하는 것을 잊었어요.

페드로: 이 코드를 누가 작성했는지 확인해 보죠, git-blame

이브: 확인하는 것도 좋긴 한데, 이 문제를 고칠 필요가 있어요.

페드로: 여기에 한 줄 추가하면 간단하죠.

이브: 제 말은, 진짜 문제를 풀자는 거에요. 같은 블럭들을 처리하는데, 비슷한 코드 2개가 왜 필요하죠?

페드로: 맞네요. 합성 패턴을 사용해서 전체 페이지 랜더링을 처리할 수 있을 것 같아요. 랜더링하는 가장 작은 요소는 블럭이구요.

public interface Block {
  void addBlock(Block b);
  List<Block> getChildren();

  void render();
}

페드로: 당연히 블럭은 다른 블럭을 포함할 수 있어요. 그게 바로 합성 패턴이죠. 구체적인 블럭 몇 개를 만들어 보죠.

public class Page implements Block { }
public class Header implements Block { }
public class Body implements Block { }
public class HeaderTitle implements Block { }
public class UserAvatar implements Block { }

페드로: 그리고 모든 구체적인 요소들을 Block인 것처럼 다룰 수 있죠.

Block page = new Page();
Block header = new Header();
Block body = new Body();
Block title = new HeaderTitle();
Block avatar = new UserAvatar();

page.addBlock(header);
page.addBlock(body);
header.addBlock(title);
header.addBlock(avatar);

page.render();

페드로: 이것은 구조 패턴이에요. 개체들을 합성하는 좋은 방법이죠. 그래서 합성이라고 불리는 거죠.

이브: 저기요. 합성은 단순한 트리 구조네요.

페드로: 그렇죠.

이브: 모든 자료구조를 위한 패턴이 있나요?

페드로: 아니요. 단지 리스트와 트리만을 위한 패턴이 있죠.

이브: 사실, 트리는 리스트로 표현할 수 있어요.

페드로: 어떻게요?

이브: 리스트의 첫 요소는 노드이고요. 그 다음 요소들은 자식들이., 그리고 그들 각각은…​

페드로: 이해했어요.

이브: 좀 더 설명하자면, 다음과 같이 트리가 있어요.

        A
     /  |  \
    B   C   D
    |   |  / \
    E   H J   K
   / \       /|\
  F   G     L M N

이브: 그리고 이 트리를 나타내는 리스트가 다음처럼 돼요.

(def tree
  '(A (B (E (F) (G))) (C (H)) (D (J) (K (L) (M) (N)))))

페드로: 괄호가 많네요!

이브: 괄호는 구조를 만드는 거죠, 알다시피.

페드로: 하지만 파악하기 어려워요.

이브: 기계한테는 쉽죠. 트리를 처리하는 tree-seq라는 멋진 함수가 있어요

(map first (tree-seq next rest tree)) => (A B E F G C H D J K L M N)

이브: 더 복잡한 순회가 필요하다면, clojure.walk를 사용하면 돼요.

페드로: 모르겠네요, 모든 것이 좀 더 어려워 보이네요.

이브: 아니요, 모든 트리를 자료구조 하나로 정의하고, 그것에 대해 동작하는 하나의 함수만을 사용하는 것이예요.

페드로: 이 함수가 하는 일이 뭐죠?

이브: 트리를 순회하면서 모든 노드에 함수를 적용하는 거죠, 우리의 경우에는 각 컴포넌트들을 랜더링하는 거구요.

페드로: 모르겠네요, 전 트리를 다루기에는 경험이 부족한가 봐요. 다음으로 가죠.


  • open/composite-pattern.txt
  • 마지막으로 수정됨: 2021/11/22 11:18
  • 저자 127.0.0.1