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. よろしくお願いします • 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
  2. interface Asset + getValue() class Cash + getValue() class Property

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

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

    + getValue() class Property + getValue() class Portfolio + getValue() + add(Asset) + remove(Asset) class AppleStock + getValue() Leaf(葉っぱ)オブジェクト
  5. 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オブジェクト
  6. A 円 C 円 D 円 E 円 F 円

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

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

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

    + add(Asset) + remove(Asset) class Cash + getValue() class Property + getValue() class Fund + getValue() + add(Asset) + remove(Asset)
  10. 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()
  11. 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
  12. • 単体/Compositeオブジェクトを同じ もののように扱える • 新しい種類のコンポーネントを追加 しやすい • Leaf(子供)に親へのリファレンスを 保管することで、階層を横断できる 例:

    child->parent->parent… • Compositeオブジェクトに保管でき る子供の型を限定しにくい(ランタイ ムに確認が必要) メリット デメリット
  13. サンプルコード 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 イメージ
  14. サンプルコード 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 イメージ
  15. 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 イメージ
  16. サンプルコード # (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" イメージ