Pythonによるデザインパターン5原則

#参考

@kidach1 さんの投稿をPythonに書き換えてるだけです。
@kidach1 さん、いつもありがとうございます。
https://qiita.com/kidach1/items/4b63de9ad5a97726c50c

#概要
改めて基本を学ぶ。
参考「Rubyによるデザインパターン第1章」→この投稿はPython

#デザインパターンとは
- プログラミングにおいて繰り返し現れる問題に対する、適切解のパターン。
- 無駄無く設計されたオブジェクト指向プログラムの実現をサポート。

パターンとしてカタログ化されていることで
車輪の再発明を防ぐ

#デザインパターンの根底にある5つの考え
- 変わるものを変わらないものから分離する
- プログラムはインターフェイスに対して行う（実装に対して行わない）
- 継承より集約
- 委譲、委譲、委譲
- 必要になるまで作るな（YAGNI）

#変わるものを変わらないものから分離する
ソフトウェアの仕様には必ず変更が加わるもの。
変わるものと変わらないものを分離しておくことで、
「仕様の変更」に対して「システムの変更」を出来る限り局所的にする。

#プログラムはインターフェイスに対して行う（実装に対して行わない）
可能な限り「一般的・抽象的なもの」に対してプログラミングすること。
（ここで言うインターフェイスは、Javaの組み込み構文としてのインターフェイスではなく、
より広いレベルで「抽象度を高めたもの」を意味する。）

これにより、全体のコードの結合度を下げる。

**具体性が高く、密結合なコード**

```python
if ( is_car()  ):
  my_car = Car()
  my_car.drive(200)
else:
  my_plane = AirPlane()
  my_plane.fly(200)
```

乗り物が増える度にコード全体に変更が必要（変更に弱い）。

抽象度が高く、疎結合なコード

```python

my_vehicle = get_vehicle()
my_vehicle.travel(200)
```

乗り物の数が増えても本コードに変更を加える必要はない（変更に強い）。

#継承より集約

継承は望ましくないつながりを作ってしまう。

具体的には

- サブクラスの振る舞いは、スーパークラスの振る舞いに依存する。
- サブクラスからスーパークラスの中身を覗くことが出来る。

```python
class Vehicle:
  def start_engine(self):
    # エンジンを動かすためのもろもろの処理..
    print("engine started")
  def stop_engine(self):
    # エンジンを止めるためのもろもろの処理..
    print("engine stopped")

class Car(Vehicle):
  def drive(self):
    self.start_engine()
    # driving..
    self.stop_engine()

car = Car()
car.drive()
```

Carからエンジンの実装が丸見え
エンジンを使用しない乗り物を作りたい場合は大改造が必要

**→変わりやすい部分（Engine）を変わりにくい部分（Vehicle）から分離できていない。**

**代替案**

*集約*を使う。
つまり、

**オブジェクトに、「他のオブジェクトに対する参照」を持たせる。**

オブジェクトが何かの一種である（is-a-kind-of）関係は避けて、
何かを持っている（has-a）関係にする。

**Car has a Engineの例**

```python
class Car:
  def __init__(self):
    self.engine = Engine()

  def drive(self):
    self.engine.start()
    # driving..
    self.engine.stop()


class Engine:
  def start(self):
    print ("engine started")
    
  def stop(self):
    print ("engine stopped")

car = Car()
car.drive()
```
これでEngineがVehicleから分離され、またカプセル化された。

これにより、Engineの手軽な切り替えが可能に。

```python
class Car:
  def __init__(self):
    self.engine = GasolineEngine()

  def drive(self):
    self.engine.start()
    # ガソリンエンジンでドライブ..
    self.switch_to_diesel()
    # ディーゼルエンジンでドライブ..
    self.engine.stop()


  def switch_to_diesel(self):
    self.engine = DieselEngine()
```

#委譲、委譲、委譲

**委譲（delegation）**
（継承パターンと同じように）start_engineとstop_engineを
クラスの外に公開したいこともある。

そんな場合でも、処理の実態はEngineクラスに任せてしまう。

```python
class Car:
  def __init__(self):
    self.engine = GasolineEngine()

  def drive(self):
    self.engine.start()
    # driving..
    self.engine.stop()

  def switch_to_diesel(self):
    self.engine = DieselEngine()

  def start_engine(self):
    self.engine.start()  # Engineクラスに任せる

  def stop_engine(self):
    self.eigine.stop()  # Engineクラスに任せる
```
これで「継承より集約」を実現しつつ、継承時と同じ機能を持つクラスが作成できた。
つまり、

**集約と委譲の組み合わせは、強力かつ柔軟な継承の代替手段。**

※ start_engineやstop_engineは委譲のために書かなければならない無駄なコードに思えるが、
*method_missing等*の利用で解決できる。
これはProxyパターンで別途詳細する。

#必要になるまで作るな（YAGNI／You Ain't Gonna Need It.）

**「将来使うかも」は、大抵使わない。**
いたずらに柔軟性を持たせようとオーバーエンジニアリングして
コードの複雑性を増していては、本末転倒。

**デザインパターン自身は目的ではない。**
問題を解決し、目的を達成するための手段として役立てるべきであり、それ以上のものではない。

デザインパターンを考える上での戒め。

#以上5原則を前提に

各パターンを見ていく。

【Template Method】-テンプレは準備した、あとはお好きに-
https://qiita.com/kotetsu75/items/2900eac0fa24f09f775b

【Strategy】-取り替え可能パーツ群を戦略的に利用せよ-
https://qiita.com/kotetsu75/items/186af7006b44703c0379

【Observer】-本日のニュースをお届けします-
https://qiita.com/kotetsu75/items/719a8fc2e4cc7789c1b4

【Composite】 -世界は再帰的（部分は全体、全体は部分）-
制作中

【Iterator】-君の子供たちに伝えたいのだけど-
制作中