alt

객체지향분석및설계 - Composite

Shared on June 14, 2026

1
Speaker 100:00

안녕하세요. 디자인 패턴에서 컴포지트 패턴을 공부하도록 하겠습니다. 컴포지트 패턴입니다. 컴포지트 패턴은 하나 이상의 일들을 복합해서 뭔가 설계에 반영을 하려고 할 때 사용을 하는 것입니다. 여기에서 한번 볼까요? 문제제기를 여기서 컨텍스트에서 했는데요. 돈에 계산을 할 때 여러가지 pricing strategy가 여러개 있는 거에요. 그 말은 뭐냐면 어떤 손님은 동네 같은 동이기 때문에 디스카운트 해주고 또 10만원 이상 산 고객은 또 몇 퍼센트 해주고 그리고 포인트가 있는 고객은 또 어떻게 해주고 그래서 여러 가지 프라이싱에 대한 스트레티지가 있을 때 이것을 복합적으로 다 적용을 해주는 그러한 컨텍스트에서 문제 제기를 하고 있습니다. 컴포지 패턴이라는 것은 여러개, 혹은 컴포지션 여러개가 합쳐진 구성된 구조죠. 그래서 하나 컴포지션이 없는 아구젯처럼 이러한 여러가지를 다 합쳐서 디스카운트를 하고 싶다는 것입니다. 그럴 때 Composite과 Atomic Object을 Define을 해서 이것을 같은 형태의 인터페이스 하에서 운영될 수 있도록 해주는 것이 솔루션입니다. 한번 교과서에서 얘기하는 솔루션을 보도록 할까요? 세일이 있죠. 물건을 구매하는 전체 형태가 있습니다. 그리고 여기에 인터페이스가 있는데요. 얘는 스트레티지, 프라이싱 스트레티지 인터페이스를 가지고 있고요. 그래서 Get Total, 스트레티지니까 여러 개의 토탈이 있는 거죠. 이렇게 토탈, 여러 토탈이 있어요. 그런데 여기에 컴포짓한 것을 하나 더 만든 겁니다. 뭐냐면은 얘는 여러 개를 해서 가장 커스텀에게 베스트인 것을 계산을 해주는 거죠. 그리고 이것은 스토아의 가장 베스트한 케이스를 계산해 주는 것입니다. 이것을 composite 해서 이 인터페이스를 다시 접근을 하는 거예요 그래서 보시게 되면 이 코드 뒤에서도 이제 나오는데요 이 composite라는 것은 다양한 스트레티지를 다 합치는 거잖아요 그래서 loop이 항상 들어갑니다 이 스트레테지를 여러개 잡아서 그것에 대한 것을 반영을 해서 그중에 가장 적절한 가격인, 가장 미니멈, 여기는 커스터머한테 가장 싼값에 줄 수 있는 스트리트지를 적용을 하는 것이라고 볼 수가 있겠습니다. 왼쪽에 보시게 되면 이 컴포지트한 프라이스 스트레티지가 바로 이 인터페이스를 또 누르고 있어요. 얘는 이 인터페이스에 인헤리트를 봤잖아요. 근데 그것을 안에 또 가지고 있어요 그래서 추가적으로 더 컴포지트를 add add 할 수가 있다는 거죠 이 부분이 바로 컨테이너 한다고 보시면 되겠습니다 여기서 보시게 되면 세일와 세일라인 아이템 물건을 여러개 구매하는거 볼 수가 있고요. 그리고 나서 composite best for customer를 부르게 되는거죠. 그러면 여러 것이 가지고 있는 스트레티지가 있어요. 룹을 돌면서 이 스트레티지 저 스트레티지를 계속해서 집어넣어서 커스터머에게 가장 좋은 가격 책정 방법을 제공을 해주는 것입니다 여기 복귀되면 이 스트레티를 통해서 다른 스테테지를 계속해서 컨테인 가지고 있다라고 보시면 되겠습니다. 자 한번 코드를 볼까요? 여기에서 iSalePriceStrategy라는 인터페이스가 있고요. 거기에 따라서 abstract 클래스를 만들었어요. 이름이 composite pricing strategy에요. 그래서 여기에 이 abstract 클래스가 있는 이유는 abstract method를 만들었어요. getTotal 그리고 여기에서 이 composite가 하는 것은 strategy를 가지고 있는데 리스트를 가지고 있어요. ArrayList. 그래서 필요에 따라서 이 스트레지에 Add, Add. Add를 해당하면 이 스트레지를 여기에다가 넣어 주는 거죠. 계속해서 필요한거에다가 Add 할 때마다. 그리고 아직 계산하는 것은 이쪽에서 구현을 안 했습니다. 그럼 composite pricing strategy가 여기죠 이거의 concrete한 클래스를 best for customer 라는 클래스를 만들었어요 여기는 여기 get total을 뭔가 계산을 해야 되는 거죠 그래서 이거를 오버라이드를 했습니다. 우선 여기서 보면 ForBeat죠. Iterative를 또 Generic으로 바꿔서 HasNex, VexNex, Drawers, Ulyses ArrayList를 Generic으로 해 주는 거죠. 그래서 스트레티지가 지금 그 다음 스트레티지를 찾는 거예요. 그 다음 스트레티지 그래서 계산을 해요. 그 다음에 계산하는 것을 가지고 토탈 민을 또 계산을 하는 거예요. 가장 작게 커스텀한테 줄 수 있는 것을 또 계산을 하는거죠. 그 다음 그 다음 그 다음 그래서 그 중에서 가장 lowest, total을 가진 상태에서 커스터머에게 제공을 하준다 라고 볼 수 있습니다 그래서 Complete Pricing에는 Add 하는거죠. 여러 스트레티지를 필요에 따라서 여기요 필요에 따라서 애드를 해줬습니다 그리고 이쪽 부분은 앞서서는 압수색으로 돼 있었었죠 그래서 여기 보면 Get Total만 오버라이트를 했습니다 그리고 이거 이외에도 다른 클래스, 콘크리트 클래스가 있으면은 거기에서 계산을 달리하면 되겠죠. 그러면 우리가 원하는 스트리티지를, 알고리즘을 계속 컴포지트하게 합쳐서 반영을 할 수가 있게 됩니다. 자, 다이나믹스를 한번 보도록 하겠습니다. 새로운 손님이 와서 세일을 시작하죠. 그래서 세일에 대한 크리에이트를 했어요. 그래서 이 물건을 구매하는 책정 결제에 대한 가격을 어떻게 할지를 팩토리를 통해서 결정을 합니다. 싱글턴이었죠. 그래서 그 중에서 커스터머에게 가장 좋은 스트레티지를 선택을 했어요. 그리고 나서 여러 스트레티지를 계속 만들어 가요. 여기는 퍼센트 디스카운트, 다른 거 그리고 나서 이제 add를 해주는 거죠. 이것도 만들어졌으면 또 add를 해주는 거죠. 여러 스트레티지를 가지고 있겠죠. 그래서 필요에 따라서 이것을 다 더해서 가장 베스트 프라이스를 제공해 줄 수 있습니다. 이러한 price strategy를 만들 때 있어서 역할, 이 색깔이 파란색보다 이 색깔이 낫네요. 다이나믹스에서 역할을 보도록 할게요. 레지스터는 외부와 내부를 익스터널과 인터널을 자르는 역할에서 컨트롤러 역할을 하는 거죠. 컨트롤 역할을 하고요. 내부에서 스토어에게 일처리를 해줬어요. 그 일을 담당하는 예를 들어서 엑스퍼트라고 했습니다. 정보를 다 알고 있는 거죠. 그래서 커스터머에 대한 정보를 이쪽에서 가지고 있고요. 그리고 나서 물건을 구입하는 거죠. 그래서 물건을 구입을 하도록 했습니다. 물건에 대한 프로덕트 정보 이쪽이 있으니까 엑스포트로 맵핑을 했습니다. 그러면 또 내부를 볼게요. 엑스포트 역할을 했죠. 그리고 팩토리에게 물건을 계산하는 스트리지를 만들고 싶습니다. 라고 해서 여기에 팩토리 패턴 줬죠. 그리고 해야 되는 일을 코에이션으로 넣어 주었습니다. 그 후에 스트레티지에 관련된 정보를 더 세부적으로 알기 위해서 커스터머에 대한 정보를 물어봐요. 엑스포트에게 그리고 현재 프라이싱 스트레티지에 관련된 우수 고객인지 뭐 그런 토탈 얼마인지 뭐 그런 것들을 이전에 물건을 구매한 파라미터도 다 이쪽으로 오게 되는 거죠. 거기에 따라서 이제 이쪽 세일에 관련된 엑스포트와 그 다음에 스트레티지, 프라이스를 측정하는 스트레티지가 Seperation 컨셉이 되어 있는 거죠. 그리고 나서 손님에게 가장 좋은 composite한 pricing strategy를 측정을 했어요. 그래서 거기에 따라서 strategy를 만들고 그 다음에 이 composite에 add 하는 거죠. 그래서 composite 패턴을 썼습니다. 물론 팩터리도 있고요 그래서 이제 좀 더 복잡해지는데요 전체 흐름에서 해야 되는 역할이 무엇이다 라는 것은 보일 수가 있겠죠

2
Speaker 211:50

컴퍼시 패턴 이어서 하도록 하겠습니다. 요거는 UML 표시가 아니구요. 트리처럼 얘가 브랜치를 해나간다 라고 보시면 되겠어요. 이렇게 생각하지 마시구요. 그래서 구성에 요소를 가지고 있는 composite object이 있는데 이것이 composite도 child로 가질 수 있고 lift도 child로 가질 수 있어요 생각을 하시면 이 폴더 우리 디렉토리 구조를 생각하시면 디렉토리 안에 디렉토리도 있고 디렉토리 안에 파일도 있는 거죠 이런 식으로 컴포짓의 가장 일반적인 케이스가 문서로 구성되어 있는 구성을 볼 수가 있습니다 구성도요 그러면 앞에서 보셨던 컴포짓 패턴을 스타릭하게 보인다 라고 보시면 되겠어요 클라이언트가 있고요 컴포지트 하는 거예요 컴포지트 하는데 이 컴포넌트에 리프 도 있고 이 컴포지트 도 있어요 얘는 마지막이죠 파일이고 이것은 폴더예요 그러니까 폴러가 또 같고 또 같고 또 같고 할 수가 있는 거죠 그래서 얘가 어그리케이션을 또 가지고 갈 수 있어요 그래서 이 어그리케이션을 가질 때 리프를 또 가질 수도 있고 얘가 또 가질 때 컴포지트를 가질 수 있고 그래서 계속적으로 다른 요소를 누적해서 가질 수 있는 구성을 볼 수가 있습니다. 인터페이스나 abstract한 클래스 위쪽에서 보시게 되면 operation, 리프가 가지고 있는 operation 다 가지고 있고요. 컴포지션이 가지고 있는 add, remove, Get Children 이런 것들도 같이 가지고 있습니다. 그래서 이 컴포넌트는 Generic Method에 일반화된 것을 가지고 있는 상태에서 얘가 Implementation 된다고 보시면 되겠습니다. Composite Pattern은 계층적인 특징을 가지고 있는 시스템이나 서브 시스템에서 우리가 흔히 볼 수 있는 그래서 아까 디렉토리 있으면 그 밑에 트리 구조라고 생각하시면 되요 디렉토리도 있고 파일도 있고 발음 파일도 있겠죠 이런 경우에 계층적인 구조를 가지고 있는 형태에서 사용할 수 있는 패턴이라고 볼 수 있으면 되겠습니다. 파일 시스템, xml, html, 그리고 다른 하이라크 핵기 구조를 예를 들어 조직체에서 hr에서 있는 구조라고 볼 수 있습니다. 여기서는 html 태그를 example로 보여주고 있어요 그래서 태그네임, start 태그, 그 다음에 end 태그 그 다음에 태그 body를 세팅하고 child 태그를 add를 해줍니다 abstract로 돼 있죠 일반화된 구조를 가지고 있습니다 remove get children return type은 list로 되어 있습니다 generate html은 구성이 안 되어 있습니다 자 이와 같은 클래스는 abstract 클래스 가장 위 아까 보면 컴포지트 위쪽에 있었던 컴포지트고 리프가 있었잖아요 이쪽은 리프, 이쪽은 컴포지트 얘는 기본적인 컴포지트 를 대표하는 거였죠 그래서 여기서는 얘는 컴포넌트 이런 식으로 했어요 이 부분을 지금 하고 있습니다 그래서 composite나 leaf 클래스에서 사용하는 이 메소드들을 이 메소드들을 여기다가 일반화해서 집어넣는다 라고 보시면 되겠어요. 왜냐하면 얘가 얘를 갖기 때문입니다. 그러면 아까 있었던 html 태그 인터페이스에서 html parent element를 define해서 이 클라스는 composite 역할을 합니다. 그래서 디렉토리처럼 계속 붙여 나갈 수 있는 거죠. constructor 여기 있고요 여기 세팅을 하고 그 다음에 태그 name 세팅 있고요 그 다음에 end 세팅하고 그리고 여기 보면은 child 태그를 add add 하죠 계속적으로 add를 할 수가 있는 구조입니다 물론 리무버 하고요 get_children 해서 현재'children'이 어떤 것이 있는지 리스트아웃 하고요 그래서 요거에 add 있죠? 'children' 태그 'children' 태그 이렇게 add 했었잖아요 그거를 리턴 해주는 거죠. 그리고 generate html 하면 프린트를 해주는데 태그 시작해서 중간 바디 있고 끝내주는 거죠. start 태그 있고 end 태그 있고 중간에 shield랑 태그 있으면 또 recursive하게 불러나가는 형태를 가지고 있습니다. 그래서 이 hdmap parent element는 composite class 구성을 가지고 있고요 children을 add 할 수도 있고 remove 할 수 있고 여기서 get을 할 수도 있습니다 그래서 다른 구성 요소를 composite class 가질 수 있도록 해주는 체계를 제공하고 있습니다 그 다음 리프를 볼까요? 리프는 동일하게 abstract한 html 태그로부터 concrete한 html element라는 이름을 갖게 되는 거구요 이 고정 요소는 필요한 거 가지고 있습니다 근데 여기서는 출드름이 없죠 약간 컴포지트한 역할은 없어요 마지막 거니까 자기 태그만 있습니다 Start 태그, End 태그, body 부분이 있고요 내용, 이렇게 태그 네임, 세팅 스타트하고 AND 하고요 BODY 그다음에 GENERATION HTML은 얘는 ROOP이 필요 없죠 START 하고 중간 BODY AND 이렇게만 있으면 돼요 그래서 마지막 리프 노드이다 라고 보시면 되겠습니다 그러면 보시게 되면 아까 composite을 이용해서 우선 parent를 만들었어요 그래서 얘는 composite을 해나가겠죠 그 다음에 parent 태그로 가지고 있습니다 그 다음에는 load parent 태그로 parent element로 p1을 만들었어요 P1을 만들어서 이 parent 태그 안에다가 P1을 집어넣었어요. 그쵸? composite 했죠. 그 다음 이쪽은 ygml-element, riff를 만들었죠. riff, child1이라고 이름을 만들었어요. 그래서 P1에다가 P1에다가 Child 1을 찍어놨어요 얘는 Converged 그 다음에 또 다른 HTML 엘리모터를 만들고 얘도 P1에 잘 돼 오늘 또 집어넣었어요 그럼 얘도 리프가 되겠죠 그래서 아까 far root인 parent tab으로부터 generate html 해라 그렇게 되면 이쪽 컴포지트 찍고 리프 두 개 있죠 이것을 나타나게 됩니다 네 그러면 리프 나타나고 전체 있는 구조도 리셜트를 가지고 있습니다