Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

よろしくお願いします ● 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

Slide 4

Slide 4 text

アジェンダ ● Compositeパターンとは ● 投資ポートフォリオの事例 ● こんな時におす すめ ● Compositeパターンの構造 ● メリット / デメリット ● サンプルコード

Slide 5

Slide 5 text

Compositeパターンとは ● GoF(Gang of Four)のデザインパターンの一つ ● 構造に関するパターン(Structural Pattern) (1994)

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

投資ポートフォリオ A 円 C 円 D 円 E 円 F 円 X 円 B 円

Slide 8

Slide 8 text

interface Asset + getValue() class Cash + getValue() class Property + getValue() class AppleStock + getValue() class Portfolio + getValue()

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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オブジェクト

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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()

Slide 18

Slide 18 text

1. 階層関係にあるオブジェクトを表現する時 2. 単体のオブジェクトと、複数のオブジェクトを持つ「Compositeオブジェクト」を同じも ののように扱いたい時 こんな時におすすめ

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

● 単体/Compositeオブジェクトを同じ もののように扱える ● 新しい種類のコンポーネントを追加 しやすい ● Leaf(子供)に親へのリファレンスを 保管することで、階層を横断できる 例: child->parent->parent… ● Compositeオブジェクトに保管でき る子供の型を限定しにくい(ランタイ ムに確認が必要) メリット デメリット

Slide 21

Slide 21 text

サンプルコード イメージ ● ファイルツリー ● 階層になっている ● チェックボックス

Slide 22

Slide 22 text

サンプルコード 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 イメージ

Slide 23

Slide 23 text

サンプルコード 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 イメージ

Slide 24

Slide 24 text

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 イメージ

Slide 25

Slide 25 text

サンプルコード # (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" イメージ

Slide 26

Slide 26 text

ご清聴ありがとうございます ブログ Strategyパターン:すべての開発 者が知っておくべき強力なツール