デザインパターン

Menu


オブジェクト指向

オブジェクト指向プログラミングには、

    対象の性質をまとめて記述する
    それを継承して再利用する

という特徴がある。関数型言語には、

    入力が決まると出力が決まる
    型の整合性

という特徴がある。

オブジェクト指向プログラミングでは、記述の方法が様々で、うまく再利用できない形になることも多い。拡張性を得るために、単に継承するだけでなく、元のソースコードを修正した方が良い場合もある。これをリファクタリングと言う。

  最初に、もっとも簡単かつ素直な実装を考える

それの必要な拡張の可能性を考える。それを用意にするデザインパターンがあれば、それを拡張が必要になった時に実装する


デザインパターン

オブジェクト指向プログラミングの定番の技術をまとめたもの。特に有用なものとして、

    State Pattern
    Factory Pattern
    Abstract Factory Pattern
    Command Pattern

をここではあげる。

    Optional ( Maybe )
    Method Chain ( Functor / fmap )
    Dependency Injection ( Monad )


交通信号の例

普通の switch 文を使った交通信号 Enum を使って状態を作り、swtich 文で状態毎の動作をする。


State Pattern

状態毎に class を使い、状態を格納する変数で切り替える。

State 自体には状態はない。

Class で状態名がわかる。


Factory Pattern

状態の次のState instance を持つようにする。

この構成のinstanceを作るために Factory method を用意する。


Abstract Factory Pattern

同じ Interface を持つインスタンスを必要に応じて選択して作成する Factory 。


Command Pattern

動作毎の class のinstanceを作り、queue に入れて、command 列の制御を行う方法。

Undo とかに使う

あるいは remote access するコマンド


Exception ではなく Optional / Maybe を使う

Monad を使うということ

Exception は実は結構遅い


病的に情報を隠すのはしない

private を default の引数みたいに使用する

プログラムの正しさが隠された情報に依存するのはだめ


Dependency Injection

classの依存性(特に transaction)を class 自体にもたせない

自分のお勧めは

  method の引数に、依存性をまとめたオブジェクト(コンテナ)を常に持たせる

dependency object を private な field に入れるのは僕は間違いだと思う


method chain

     a.method_of_a(x).metho_of_some(y) ;

みたいに呼び出す。fmap。エラー処理はどうする? ( Optional )


Anti Pattern

やってはいけないこと。ここでは、

    デザインパターンを目標にコードを書く
    大域変数
    Singleton
    1,2… 動きません
    コードのコピペ
    継承したクラス間の強い依存性
    継承したクラス同士での同じ名前のprivate変数
    ad-hoc な port の利用

をあげる。


デザインパターンを目標にコードを書かない

if 文 switch 文ですむなら、無理にデザインパターンを使わない方が良い。デザインパターンは複雑なコードに対するcompromise であり、それを目標して、コードを歪めない。


Singleton / 大域変数を使わない

Singleton と大域変数は基本的に不要。(log 以外はすべて除去)大域変数は、基本的に必要ない。例外は、stdout や log などだけ。大域変数があったら、

    なぜ、その変数は大域でなければならないのか説明する

説明できないなら除去する。

理由  並列処理でめんどう ( Thread Local も trouble ことが多い)  プログラム全体の依存度をあげてしまう

Read Only なら


局所変数の再代入をしない

局所変数を使いまわさない。インスタンスの状態以外は局所変数ですます。

値を変えたら新しい変数に代入する。

オブジェクトの状態を表す変数は、method により一回だけ変更する。


オブジェクトの private変数を使わない

継承したクラス同士での同じ名前があると複数作られる。

オブジェクトの状態は setter/getter でアクセスできるようにする。

同じ名前の複数の変数を一つのインスタンスの中で使わない。


初期化と宣言を別にしない

初期化されない変数がないようにする。必要なところで宣言する。

基本的に定数 / Readonly で使う。値を変更したければ新しく変数を作る。

    i = i + 1 ではなくて、
    j = i + 1 とする


「1,2… 動きません」にしない

複数のインスタンスがあっても動作するようにする。

コードの拡張を予測し、それを阻害しないコードにしておく。

大域変数/Singletonが「1,2… 動きません」の原因であることが多い。


コードのコピペをしない

コピペして少し変更したコードを、後で変更したらどうなるかを考える。コピペは基本的に悪。

    同じことを二箇所に書かない


ad-hoc な port の利用をしない

TCP/IP の port は動的に確保する。その port が空いてない場合を意識してプログラムする。


interface / implementtion

に機能を付け加える時は、両方を変更する必要がある

階層をまたぐと、それ全部を変更する必要がある

機能を追加する時に

  interfaceの実装を増やす

みたいにすると避けられる


引数の異なる同じな前の method が大量にあり、動作が異なる

default とかで避けようとする

そうではなくて、引数をまとめて Object にする

それを渡す

そうすると引数は一つですむ


Shinji KONO / Wed Jun 15 13:57:45 2022