前の関連記事:linuxBean14.04(170)Pythonのデスクリプタの学習を少し
JavaインターフェイスをPythonの多重継承に置換する
python-patterns/strategy_headfirst.py at 5a0689ef410d297a5cde0f6857014e4b59a50000 · p--q/python-patterns
linuxBean14.04(170)Pythonのデスクリプタの学習を少しの内容を受けて、JavaのインターフェイスをPythonの多重継承にしました。
だけど「Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本」のp5には継承はいまいち、と書いてあります、Javaでの話ですが。
抽象クラス(Duck)にメソッドを追加すると、すべての具象クラスでメソッドをオーバーライドする手間が増えるので保守の観点からは適切ではないと書いてあります。
「自分で考えてみよう」の答えは、A.コードがサブクラス間で重複する、D.すべての鴨の振舞いを把握するのが困難である、F.変更によって無意識に他の鴨に影響を与える可能性がある、ということですかね。
Sharpen Your Pencil - Head First Design Patterns page 5に答えがありました。
B.実行時の振舞いを変更するのが困難である、も答えでした。
p9に解説に該当する説明があります。
Pythonの上記のコードで該当するデメリットは、なさそうですけど。
多重継承の代わりにコンポジションを利用する
コンポジションにするために、多重継承しているクラスを、クラスの中でインスタンス化してそのメソッドを使うように変更しました。
python-patterns/strategy_headfirst.py at d2c1de5b6ceeef9b48550e87cf74fb8b44ddce8a · p--q/python-patterns
ちゃんとコンポジションになっていますが、かなり複雑なUML図になっています。
python-patterns/strategy_headfirst.py at 459c9313295f343cd8540fd1a7e145e4554d1f64 · p--q/python-patterns
QuackBehaviorクラスのメソッドはどれもインスタンス変数を使っていないので、インスタンス化せずに静的メソッドにしました。
そうするとクラス名の属性でメソッドを呼び出して実行できるようになります。
staticmethod()は使わなくても実行できますが、使わないとPyDevでエラーと言われるのでデコレーターの@staticmethodを付けました。
UML図ではQuackBehaviorクラスはインスタンス化していないので、枝が表示されていません。
コンポジションに代わって集約を利用する
composition and aggregation in python - Stack Overflow
Pythonの「コンポジション」と「集約」の例がありました。
クラスの中でインスタンス化しなければ「集約」と判断されるようです。
python-patterns/strategy_headfirst.py at 924a5f9a693d71c93fa7c6373d2023874bccefa7 · p--q/python-patterns
FlyBehaviorクラスをDuckサブクラスの外でインスタンス化して引数で渡すようにしました。
「集約」の枝を表示させたかったのですが、どういうコードにすれば「集約」の枝を表示してくれるのかわかりませんでした。
pylint/writer.py at master · PyCQA/pylint
pyreverseのソースを見ても、arrowhead='diamond', style='solid'というのしか見つけられなかったので、「集約」の枝は用意されていないのかもしれません。
結局多重継承できるPythonでは、素直に多重継承を使うのが一番すっきりしたコードになるように思いました。
参考にしたサイト
composition and aggregation in python - Stack Overflow
Pythonでの「コンポジション」と「集約」の例。
pylint/writer.py at master · PyCQA/pylint
pyreverseのソース。「集約」の枝は用意されていないように思えます。
0 件のコメント:
コメントを投稿