Composite Pattern
- 컴퓨터의 파일 시스템에는 디렉터리라는 것이 있고, 디렉터리 안에는 파일이 있거나 다른 하위 디렉터리가 있기도함
- 하위 디렉터리 안에는 또다른 하위 디렉터리가 있음
- 마치 상자안의 상자 같은 구조. 즉 재귀적 구조를 가짐
- 디렉터리 엔트리를 차례대로 조사할때, 그릇과 내용물을 같은 종류로 취급하면 편리할 수 있음
- 그릇을 내용물과 동일시하여 재귀적인 구조를 만들기 위한 디자인 패턴을 composite 패턴이라고 함.
- 한 object의 그룹과 그 object의 싱글 instance가 같은 타입으로 취급되는 패턴
- composite pattern을 통해 object들을 트리 구조로 구성할 수 있음
- 하나의 object와 그 object가 들어있는 group을 같은 타입으로 취급한다.
- group의 네모칸들은 리스트로, 이 안에 object가 들어간다.
- 이둘을 같은 타입으로 취급한다는 말은 둘이 같은 interface를 가지고 있다는 뜻
Leaf의 역할 : leaf는 내용물을 표시하는 역할을 하며 내부에는 다른것을 넣을 수 없음
composite의 역할을 하며 leaf역할이나 composite 역할을 넣을 수 있음
component의 역할 : leaf역할과 composite 역할을 동일시 하기 위한 역할을 하며.
component는 leaf 역할과 composite 역할에 공통적인 상위 클래스로 실현함
- composite pattern 에서는 이러한 base interface를 component, 상속받은 객체를 leaf, 이를 상속받은 그룹을 composite이라고 함.
- composite 안의 list에는 component 객체가 들어감
- component 가 들어간다면 이 리스트 안에는 결국 leaf, composite 모두 들어갈 수 있는 것(component를 상속받은 객체들이므로)
- component 를 상속받은 leaf와 composite은 component와 같은 함수를 가지고 있어야 함.
component class
- base interface
- fn 함수를 가지고 있음
leaf class
- component 를 상속받음
- fn을 통해 leaf 출력
composite class
- component를 상속받음
- component 객체의 list인 components 존재
- add() : components 리스트에 component 추가하는 기능
- fn은 "composite"출력하고 components list 내부에 있는 element 하나씩 불러서 각 개체에 대해 fn 함수 호출
- composite object 인 compst1 생성
- 그 안에 leaf 2개 삽입
- composite object인 compst() 생성
- compst()은 leaf 1개와 compst1을 소유하고 있음
- 마지막으로 compst()에서 fn함수 호출
compst() 안에 있는 모든 object에 대해서 fn함수 호출된 것을 확인할 수 있음
다시말해서 트리구조에서 루트를 기점으로 함수 fn을 호출하여 그 안에 들어있는 모든 object에 대해 함수 fn이 퍼져나간 형태
->
composite pattern의 장점은 트리 구조가 매우 복잡할 때 트리 투르에서 함수 하나만 호출하면 composite pattern을 따라서 leaf 까지 그 함수가 자동으로 호출됨
Animal class
- base interface
- speak 함수를 가지고 있음
cat class
- Animal 상속받음
- speak를 통해 meow 출력
Dog class
- Animal 상속받음
- speak를 통해 bark 출력
AnimalGroup class
- Animal 상속받음
- Animal 객체의 list인 animals 존재
- add() : animals 리스트에 Animal 객체 추가하는 기능
- speak()는 group speaking.. 출력하고
animals list 내부에 있는 element 하나씩 불러 각 개체에 대해 speak 함수 호출
zoo에서 speak 함수 호출하여 그 내부에 들어있는 모든 object에 대해서 speak 함수 호출
⬇️
compoiste pattern 의 핵심은 그룹과 오브젝트가 같은 인터페이스를 제공함으로써
루트에서부터 시작하여 함수가 트리안에 있는 모든 함수로 퍼지는 구조
class Office: #component class
totalQuantity = 0
def __init__(self):
self.quantity = 0
self.branchName = ""
def branchSpecificService(self): #composite pattern fn()
pass
def setName(self, name):
self.branchName = name
def setQuantity(self, quantity):
self.quantity = quantity
def report(self):
print(self.branchName, ": ", self.quantity)
Office.totalQuantity = Office.totalQuantity + self.quantity
class PusanOffice(Office): #leaf class1
def branchSpecificService(self): #composite pattern fn()
print("Pusan service")
class DaeguOffice(Office): #leaf class 2
def branchSpecificService(self): #composite pattern fn()
print("Daegu service")
class GwangjuOffice(Office): #leaf class 3
def branchSpecificService(self): #composite pattern fn()
print("Gwangju service")
class GroupOffice(Office): #composite class
def __init__(self):
self.components = [] #composite pattern
def add(self, component:Office):
self.components.append(component) #composite pattern
return self
def getTotalQuantity(self):
print(self.branchName, Office.totalQuantity)
def branchSpecificService(self): #composite pattern fn()
for office in self.components:
office.branchSpecificService()
office.report()
#부산지역
p1 = PusanOffice()
p1.setName("부산 1호점")
p1.setQuantity(500000)
p2 = PusanOffice()
p2.setName("부산 2호점")
p2.setQuantity(350000)
p3 = PusanOffice()
p3.setName("부산 3호점")
p3.setQuantity(700000)
groupPusan = GroupOffice()
groupPusan.setName("부산지사")
groupPusan.setQuantity(0)
groupPusan.add(p1).add(p2).add(p3)
#대구지역
d1 = DaeguOffice()
d1.setName("대구 1호점")
d1.setQuantity(400000)
d2 = DaeguOffice()
d2.setName("대구 2호점")
d2.setQuantity(400000)
groupDaegu = GroupOffice()
groupDaegu.setName("대구지사")
groupDaegu.setQuantity(0)
groupDaegu.add(d1).add(d2)
#광주지역
g1 = GwangjuOffice()
g1.setName("광주 1호점")
g1.setQuantity(300000)
g2 = DaeguOffice()
g2.setName("광주 2호점")
g2.setQuantity(500000)
groupGwangju = GroupOffice()
groupGwangju.setName("광주지사")
groupGwangju.setQuantity(0)
groupGwangju.add(g1).add(g2)
#본사
Head = GroupOffice()
Head.setName("본사")
Head.setQuantity(-1)
Head.add(groupPusan).add(groupDaegu).add(groupGwangju)
Head.branchSpecificService() # <--이게 호출됨으로서 연결되어있는 모든 leaf들이 딸려나옴
Head.getTotalQuantity()