As i wish

[Design pattern] Composite pattern (컴포지트 패턴) 본문

Design Pattern

[Design pattern] Composite pattern (컴포지트 패턴)

어면태 2019. 5. 23. 11:06

안녕하세요.

오늘은 컴포지트 패턴에 대하여 공부해보겠습니다.

 

컴포지트 패턴
객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들수 있다. 클라이언트에서 개별 객체와 다른 객체들로 구성된 복합 객체(composite)를 똑같은 방법으로 다룰 수 있다.

 

쉽게 말해 컴퓨터의 디렉토리 구조라고 생각하시면 됩니다.

컴퓨터에 어떤 디렉토리가 있다고 가정 했을 때, 디렉토리 안에는 디렉토리가 있을 수도 있고, 파일이 있을수도 있죠. 근데 클라이언트 입장에서는 이게 디렉토리인지, 파일인지 구분 없이 만들 수 있게 되어야 합니다.

즉, 클라이언트는 개별 객체(파일), 복합 객체(디렉토리) 를 같은 방법으로 다룰 수 있어야 합니다.

 

 

그럼 저는 헤드퍼스트에 나온 예제를 참고하여, 메뉴로 구성해 보겠습니다.

위에서 언급한것과 마찬가지로 디렉토리는 Menu가 되겠고요, 파일은 Menu가 되겠죠. 각각의 두 객체는 MenuComponent로 부터 상속 받게 됩니다.

그럼 바로 코드로 보시죠!

# -*- coding: utf-8 -*-
# Composite Pattern

import abc

class MenuComponent:
  __metaclass__ = abc.ABCMeta

  def getName(self):
    pass

  def getDescription(self):
    pass

  def getPrice(self):
    pass

  def isVegetarian(self):
    pass

  def printMenu(self):
    pass

  def add(self, component):
    pass

  def remove(self, componet):
    pass

class Waitress:
  def __init__(self, menu):
    self.menu = menu

  def printMenu(self):
    self.menu.printMenu()

class MenuItem(MenuComponent):
  def __init__(self, name, description, vegetarian, price):
    self.name = name
    self.description = description
    self.vegetarian = vegetarian
    self.price = price

  def getName(self):
    return self.name;

  def getDescription(self):
    return self.description

  def getPrice(self):
    return self.price

  def isVegetarian(self):
    return self.vegetarian

  def printMenu(self):
    print (" %s , " %self.getName())
    print (" %s , " %self.getPrice())
    print (" %s , " %self.getDescription())

class Menu(MenuComponent):
  def __init__(self, name, description):
    self.menuComponents = []
    self.name = name
    self.description = description

  def getName(self):
    return self.name

  def getDescription(self):
    return self.description

  def add(self, component):
    self.menuComponents.append(component)

  def printMenu(self):
    print ("%s , " %self.getName())
    print ("%s , " %self.getDescription())
    print ("----------------------------")

    for menuComponent in self.menuComponents:
      menuComponent.printMenu();
      print('\n')


# Client
pancakeHouseMenu = Menu('PANCAKE HOUSE MENU', 'Breakfirst MENU')
dinerMenu = Menu('DINER MENU', 'Lunch MENU')
cafeMenu = Menu('CAFE MENU', 'Dinner MENU')
dessertMenu = Menu('DESSERT MENU', 'Enjoy dessert!')

allMenus = Menu('ALL MENU', 'All Menu')
allMenus.add(pancakeHouseMenu)
allMenus.add(dinerMenu)
allMenus.add(cafeMenu)

pancakeHouseMenu.add(MenuItem('K&B PancakeSet', 'Scrable egg and toast', True, 2.99))

dinerMenu.add(MenuItem('Pasta', 'Tomato-source Past', True, 3.89))
dinerMenu.add(dessertMenu)

cafeMenu.add(MenuItem('Americano', 'Basic Coffee', True, 1.99))

dessertMenu.add(MenuItem('Apple Pie', 'Apple pie with IceCream', True, 1.59))

waitress = Waitress(allMenus)
waitress.printMenu()





위 코드 처럼 Client는 개별 객체(MenuItem) 이던 복합 객체(Menu)등 상관 없이 사용 하게 되고, 각각의 메서드 들도 사용하게 됩니다.

Waitress에서 print를 했을 시에는 사실 잘 보시면 아시겠지만 약간 재귀처럼 불립니다. menuComponents에서 반복해서 menuComponent를 확인하고 만약 menuComponent가 복합 객체이면 개별 객체가 나올 때 까지 for loop 가 돈다고 볼 수 있겠습니다.

따라서 앞서 포스팅 했던 이터레이터 패턴도 적용 할 수 있겠죠.

 

Comments