파이썬에서 디자인 패턴 "Composite"를 배우십시오.

GoF의 디자인 패턴을 학습하는 소재로서, 서적 「 증보 개정판 Java 언어로 배우는 디자인 패턴 입문 」가 참고가 되는 것 같네요. 다만, 다루어지고 있는 실례는, JAVA 베이스이기 때문에, 자신의 이해를 깊게 하기 위해서도, Python에서 동등의 프랙티스에 도전해 보았습니다.

■ Composite(컴포지트·패턴)



Composite 패턴(컴포지트 패턴)은 GoF(Gang of Four; 4명의 갱들)에 의해 정의된 디자인 패턴의 하나이다. "구조에 관한 패턴"에 속한다. Composite 패턴을 사용하면 디렉토리와 파일 등과 같은 트리 구조와 관련된 재귀 데이터 구조를 나타낼 수 있습니다.
Composite 패턴에서 등장하는 객체는 "가지"와 "잎"이며, 이들은 공통 인터페이스를 구현합니다. 그 때문에, 가지와 잎을 마찬가지로 취급할 수 있다는 장점이 있다.

UML class and object diagram





UML 클래스 diagram




(이상 위키피디아(Wikipedia)에서 인용)

□ 비망록



서적 「증보 개정판 Java 언어로 배우는 디자인 패턴 입문」의 인용입니다만, 배고파졌습니다.

일부 디렉토리에는 파일이 있거나 다른 디렉토리(하위 디렉토리)가 들어 있습니다. 그리고 일부 하위 디렉토리에는 다른 파일과 하위 디렉토리가 포함되어 있습니다.
디렉토리는 그러한 "중첩"이 된 구조, 재귀 구조를 생성합니다.
... (snip)
Composite 패턴은, 이러한 구조를 만들기 위한 것이며, 용기와 내용물을 동일시해, 재귀적인 구조를 만드는 디자인 패턴

■ "Composite" 샘플 프로그램



실제로 Composite 패턴을 활용한 샘플 프로그램을 움직여서 다음과 같은 동작의 모습을 확인하고 싶습니다.
  • 루트 항목의 ディレクトリサブディレクトリファイル를 추가해보십시오.
  • 루트 항목의 ディレクトリ에 사용자 항목의 ディレクトリ를 추가하고 サブディレクトリファイル를 추가 해보십시오.
  • 어쨌든 ファイルディレクトリ를 추가하여 실패하는지 확인하십시오
  • $ python Main.py 
    Making root entries...
    /root (30000)
    /root/bin (30000)
    /root/bin/vi (10000)
    /root/bin/latex (20000)
    /root/tmp (0)
    /root/usr (0)
    
    Making user entries...
    /root (31500)
    /root/bin (30000)
    /root/bin/vi (10000)
    /root/bin/latex (20000)
    /root/tmp (0)
    /root/usr (1500)
    /root/usr/yuki (300)
    /root/usr/yuki/diary.html (100)
    /root/usr/yuki/Composite.java (200)
    /root/usr/hanako (300)
    /root/usr/hanako/memo.tex (300)
    /root/usr/tomura (900)
    /root/usr/tomura/game.doc (400)
    /root/usr/tomura/junk.mail (500)
    
    Occurring Exception...
    FileTreatmentException
    

    ■ 샘플 프로그램에 대해 자세히 알아보기



    Git 저장소에도 비슷한 코드가 있습니다.
    htps : // 기주 b. 코 m / 츠 츠보 / s dy _ f_ shin gn_pate rn / t ree /
  • 디렉토리 구성
  • .
    ├── Main.py
    └── entry.py
    

    (1) Leaf(잎)의 역



    「내용」을 나타내는 역입니다. 이 역할 중에는 다른 것을 넣을 수 없습니다.
    샘플 프로그램에서는, File 클래스가, 이 역할을 노력합니다.

    entry.py
    class File(Entry):
        def __init__(self, name, size):
            self.name = name
            self.size = size
    
        def getName(self):
            return self.name
    
        def getSize(self):
            return self.size
    
        def _printList(self, prefix=''):
            print("{0}/{1}".format(prefix, self))
    

    (2) Composite(복합체)의 역할



    「용기」를 나타내는 역입니다. Leaf 역할이나 Composite 역할을 넣을 수 있습니다.
    샘플 프로그램에서는, Directory 클래스가, 이 역할을 노력합니다.

    entry.py
    class Directory(Entry):
        def __init__(self, name):
            self.name = name
            self.directory = []
    
        def getName(self):
            return self.name
    
        def getSize(self):
            size = 0
            for d in self.directory:
                size += d.getSize()
            return size
    
        def add(self, entry):
            entry.path = self.name
            self.directory.append(entry)
    
        def _printList(self, prefix=''):
            print(prefix + "/" + str(self))
            for e in self.directory:
                e._printList(prefix + '/' + self.name)
    

    (3) Component의 역할


    Leaf 역과 Composite 역을 동일시하기 위한 역입니다. Component 역은 Leaf 역과 Composite 역에 공통의 슈퍼 클래스로서 실현합니다.
    샘플 프로그램에서는, Entry 클래스가, 이 역할을 노력합니다.

    entry.py
    from abc import ABCMeta, abstractmethod
    
    ... (snip)
    
    class Entry(metaclass=ABCMeta):
        @abstractmethod
        def getName(self):
            pass
    
        @abstractmethod
        def getSize(self):
            pass
    
        def add(self, entry):
            raise FileTreatmentException
    
        def printList(self):
            self._printList()
    
        @abstractmethod
        def _printList(self, prefix=''):
            pass
    
        def __str__(self):
            return "{0} ({1})".format(self.getName(), self.getSize())
    

    (4) Client(의뢰인)의 역할



    샘플 프로그램에서는, startMain 메소드가, 이 역할을 노력합니다.

    Main.py
    from abc import ABCMeta, abstractmethod
    from entry import Directory, File, FileTreatmentException
    
    
    def startMain():
        try:
            print("Making root entries...")
            rootdir = Directory("root")
            bindir = Directory("bin")
            tmpdir = Directory("tmp")
            usrdir = Directory("usr")
    
            rootdir.add(bindir)
            rootdir.add(tmpdir)
            rootdir.add(usrdir)
    
            bindir.add(File("vi", 10000))
            bindir.add(File("latex", 20000))
            rootdir.printList()
    
            print("")
            print("Making user entries...")
            yuki = Directory("yuki")
            hanako = Directory("hanako")
            tomura = Directory("tomura")
    
            usrdir.add(yuki)
            usrdir.add(hanako)
            usrdir.add(tomura)
    
            yuki.add(File("diary.html", 100))
            yuki.add(File("Composite.java", 200))
            hanako.add(File("memo.tex", 300))
            tomura.add(File("game.doc", 400))
            tomura.add(File("junk.mail", 500))
            rootdir.printList()
    
            print("")
            print("Occurring Exception...")
            tmpfile = File("tmp.txt", 100)
            bindir = Directory("bin")
            tmpfile.add(bindir)
        except FileTreatmentException as ex:
            print(ex.message)
    
    if __name__ == '__main__':
        startMain()
    

    (5) 기타



    예외 클래스 추가

    entry.py
    class FileTreatmentException(Exception):
        def __init__(self,*args,**kwargs):
            self.message = "FileTreatmentException"
    

    ■ 참고 URL


  • 「Java 언어로 배우는 디자인 패턴 입문」을 끝내고(없음)
  • 좋은 웹페이지 즐겨찾기