Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Compositeパターン: オブジェクトの階層関係をエレガントに表現する方法

Hank Ehly
November 25, 2022

Compositeパターン: オブジェクトの階層関係をエレガントに表現する方法

Hank Ehly

November 25, 2022
Tweet

More Decks by Hank Ehly

Other Decks in Technology

Transcript

  1. None
  2. Compositeパターン オブジェクトの階層関係をエレガントに表現する方法 2022/11/25 (金)

  3. よろしくお願いします • Hank Ehly(名:ハンク 姓:イーリー) • ENECHANGE株式会社 ◦ 節電目的で家電を遠隔操作するアプリケーション開発 ◦

    大量の電力消費量データを用いたクラスター分析/予測システム開発 ◦ Airflowを活用したデータパイプライン開発 ◦ AWS Elastic Container Serviceで1,000以上のFargateノードを活用した 分散処理 • qiita.com/hankehly • github.com/hankehly • linkedin.com/in/hankehly • twitter.com/hankehly • connpass.com/user/hankehly
  4. アジェンダ • Compositeパターンとは • 投資ポートフォリオの事例 • こんな時におす すめ • Compositeパターンの構造

    • メリット / デメリット • サンプルコード
  5. Compositeパターンとは • GoF(Gang of Four)のデザインパターンの一つ • 構造に関するパターン(Structural Pattern) (1994)

  6. Compositeパターンとは • 階層関係にあるオブジェクトをエレガントに表現し、扱い方をシンプルに • オブジェクトを木構造にまとめる • 単体のオブジェクトと、複数のオブジェクトを持つ 「Compositeオブジェクト」を同じもののように扱うこと が可能になる A

    B C D E Compositeオブジェクト 単体のオブジェクト
  7. 投資ポートフォリオ A 円 C 円 D 円 E 円 F

    円 X 円 B 円
  8. interface Asset + getValue() class Cash + getValue() class Property

    + getValue() class AppleStock + getValue() class Portfolio + getValue()
  9. interface Asset + getValue() + add(Asset) + remove(Asset) class Cash

    + getValue() class Property + getValue() class Portfolio + getValue() + add(Asset) + remove(Asset) class AppleStock + getValue()
  10. interface Asset + getValue() + add(Asset) + remove(Asset) class Cash

    + getValue() class Property + getValue() class Portfolio + getValue() + add(Asset) + remove(Asset) class AppleStock + getValue() Leaf(葉っぱ)オブジェクト
  11. interface Asset + getValue() + add(Asset) + remove(Asset) class Cash

    + getValue() class Property + getValue() class Portfolio + getValue() + add(Asset) + remove(Asset) class AppleStock + getValue() Leaf(葉っぱ)オブジェクト Compositeオブジェクト
  12. A 円 C 円 D 円 E 円 F 円

    X 円 B 円
  13. A 円 C 円 D 円 E 円 F 円

    B 円 class Portfolio + getValue() + add(Asset) + remove(Asset)
  14. C 円 D 円 E 円 F 円 B 円

    class Portfolio + getValue() + add(Asset) + remove(Asset) class Cash + getValue()
  15. C 円 D 円 E 円 F 円 class Portfolio

    + getValue() + add(Asset) + remove(Asset) class Cash + getValue() class Property + getValue()
  16. D 円 E 円 F 円 class Portfolio + getValue()

    + add(Asset) + remove(Asset) class Cash + getValue() class Property + getValue() class Fund + getValue() + add(Asset) + remove(Asset)
  17. class Portfolio + getValue() + add(Asset) + remove(Asset) class Cash

    + getValue() class Property + getValue() class Fund + getValue() + add(Asset) + remove(Asset) … class AppleStock + getValue() class EnechangeStock + getValue()
  18. 1. 階層関係にあるオブジェクトを表現する時 2. 単体のオブジェクトと、複数のオブジェクトを持つ「Compositeオブジェクト」を同じも ののように扱いたい時 こんな時におすすめ

  19. Compositeパターンの構造 • Component (Asset) ◦ 階層にあるオブジェクトのI/F定義 ◦ デフォルト挙動の実装 ◦ 子供を取得したり、管理するためのI/F定義

    operation() add(Component) remove(Component) getChild(int) Component operation() Leaf Client for c in self.children: c.operation() • Leaf (Cash) ◦ 単体のオブジェクトを表現する ◦ 単体のオブジェクトの実装 ◦ 子供を持たない • Composite (Fund) ◦ 子供を持つオブジェクトの実装 ◦ 子供を管理するロジックの実装 ▪ 例: add, remove, getChild ◦ 子供を保管する • Client ◦ Component I/Fを通じてオブジェクトを操る operation() add(Component) remove(Component) getChild(int) Composite 1 parent 0..* child
  20. • 単体/Compositeオブジェクトを同じ もののように扱える • 新しい種類のコンポーネントを追加 しやすい • Leaf(子供)に親へのリファレンスを 保管することで、階層を横断できる 例:

    child->parent->parent… • Compositeオブジェクトに保管でき る子供の型を限定しにくい(ランタイ ムに確認が必要) メリット デメリット
  21. サンプルコード イメージ • ファイルツリー • 階層になっている • チェックボックス

  22. サンプルコード class PathComponent: """Componentインターフェイス """ def __init__(self, name): self.name =

    name def add(self, child: "PathComponent"): pass def remove(self): pass def set_checked(self, checked): pass def get_checked(self): pass イメージ
  23. サンプルコード class FileLeaf(PathComponent): """Leafクラス""" def __init__(self, name): super().__init__(self, name) self.checked

    = Checked.Unchecked def add(self, child: PathComponent): raise NotImplementedError() def remove(self, child: PathComponent): raise NotImplementedError() def set_checked(self, checked): self.checked = checked def get_checked(self): return self.checked イメージ
  24. class CompositeFolder(PathComponent): """Compositeクラス""" def __init__(self, name): super().__init__(self, name) self.children =

    set() def add(self, child: PathComponent): self.children.add(child) def remove(self, child: PathComponent): if child in self.children: self.children.remove(child) def set_checked(self, checked): for c in self.children: c.checked = checked def get_checked(self): child_status = [] for c in self.children: # Compositeはオペレーションを子供に委託する child_status.append(c.get_checked()) if all(child_status): return Checked.Checked elif all([s == False for s in child_status]): return Checked.Unchecked else: return Checked.Intermediate イメージ
  25. サンプルコード # (1) コンポーネントを作る first_child = FileLeaf("First Child") second_child =

    CompositeFolder("Second Child") grandchild_1 = FileLeaf("Grandchild 1") grandchild_2 = CompositeFolder("Grandchild 2") grand_grandchild_1 = FileLeaf("GrandGrandchild 1") grand_grandchild_2 = CompositeFolder("GrandGrandchild 2") grandchild_3 = FileLeaf("Grandchild 3") third_child = FileLeaf("Third Child") # (2) 階層を作る grandchild_2.add(grand_grandchild_1) grandchild_2.add(grand_grandchild_2) second_child.add(grandchild_1) second_child.add(grandchild_2) second_child.add(grandchild_3) # (3) コンポーネントを操る # *Leaf/Compositeの区別不要* grandchild_1.set_checked(Checked.Checked) grand_grandchild_1.set_checked(Checked.Checked) second_child.get_checked() # "intermediate" イメージ
  26. ご清聴ありがとうございます ブログ Strategyパターン:すべての開発 者が知っておくべき強力なツール