デザインパターンの話
背景
いや何度見ても忘れるので。何度も見るようなものくらいは覚えておこうかなと。
参考
Singleton Pattern
要するにProgram中で唯一のinstanceであることを保証する仕組み。
例: Mojo
Mojo::IOLoop · yuki-kimoto/mojolicious-guides-japanese Wiki · GitHub
Mojoだとevent loopにsingletonというのがあって、これがserver側のevent loopのglobalなobjectとして定義されている。新しく作ったevent loopをここにつなぎ込むことでどこからでもaccessできる。
perlでのSingletonなclassの実装
そういえばいろんなcommandを作ったりdaemonを作ったりしていた結果共通のLoggerが欲しくなって作ったことがあったんだけど、これ、考えてみればsingletonで構成すればpythonのloggerみたく使えるんじゃないか?
ということをふと思いついたので実際層なのかはともかくperlでのsingleton patternでのclass定義の方法を調べる。
How can I implement a singleton class in perl? - Stack Overflow
package MySingletonClass; use strict; use warnings; use feature 'state'; sub new { my ($class) = @_; state $instance; if (! defined $instance) { $instance = bless {}, $class; } return $instance; }
featureってなんだ。
feature - 新しい構文上の機能を有効にするプラグマ - perldoc.jp
既に存在しているプログラムを壊すことなく、Perl に新しい文法を追加することは、 普通は不可能です。 このプラグマは、リスクを最小化する方法を提供します。 新しい文法構造は use feature ‘foo’ で有効化され、適切な feature プラグマが スコープ内にある場合にのみパースされます。
わからん。
use feature ‘state’ は、コンパイラに state 変数を有効にするように 伝えます。
state変数とは?
Perlの組み込み関数 state の翻訳 - perldoc.jp
state はちょうど my と同様に、レキシカルなスコープの変数を宣言します。 しかし、レキシカル変数がブロックに入る毎に再初期化されるのと異なり、 この変数は決して再初期化されません。 詳しくは “Persistent Private Variables” in perlsub を参照してください。
ああそういうこと。なるほど。理解できた。
Visitor Pattern
13.Visitor パターン | TECHSCORE(テックスコア)
Visitor パターンでは、このように、受け入れる側に処理を追加することなく、処理を追加することができるパターンです。
わかったようなわからないような。というかこのpageの説明が僕と相性が悪い。たとえを出すならそのまま実用的なexampleを一つ出して欲しい。
概念の説明のためのふわっとした例での説明をされると大体混乱する。ああ学校の授業が苦手だった理由がわかった……。確かに「で、それって何に使う物なの?」というのがわからないと全く記憶できなかった……。そうか……。そうだったのか……。
ということでまた何か例を探そう。
複雑な構造体の中身を要素ごとに処理していくための構成……。どういうことさ。
Visitor パターンは、データ構造と振る舞いを別々のクラスに扱わせて、振る舞いの変更や追加、拡張を可能にするパターンです。
言ってることが一番わかりやすいのはここかな。
pythonでもいいから何か例がないかな。
- 作者: Tarek Ziade,稲田直哉,渋川よしき,清水川貴之,森本哲也
- 出版社/メーカー: KADOKAWA/アスキー・メディアワークス
- 発売日: 2010/05/28
- メディア: 大型本
- 購入: 33人 クリック: 791回
- この商品を含むブログ (92件) を見る
この本にあった。algorithmとdata structureを分離できるとある。
先の引用とあわせて、やりたいこととしてはそういうことだ、というのはわかってきた。
で、既存のclassからalgorithmを取りだしてvisitor classとして定義することでこれを実現しているらしい。なるほど。構造体とlogicをわけるみたいな感じ。関数pointerとかでくっつけてたりもできるけどそうではなく。
で、こうすることでvisitorを切り替えることで別の処理も実現できる、と。ああなるほどだから大きなdata structureからreportを生成するときとかにも有用、と。
理解できた。
Strategy Pattern
そもそもがこの記事書くきっかけがこれだったな。
10. Strategy パターン | TECHSCORE(テックスコア)
普通にプログラミングしていると、メソッドの中に溶け込んだ形でアルゴリズムを実装してしまうことがよくあります。if 文などで分岐させることでアルゴリズムを変更するような方法です。Strategy パターンでは、戦略の部分を意識して別クラスとして作成するようにしています。
確かにきっかけとなった記事にもifの分岐で中身が大量に書かれているような時に使うみたいな話があった。
で、どういうのもなんだ。
たとえば、メモリ実装状態により、「メモリを使うアルゴリズム」か「ディスクを使うアルゴリズム」かを動的に切り分ける時に有効ですね。
あー。なるほど。だからalgorithmの変更なわけか。処理とかmethodの切り替えというわけじゃなくて(そういう粒度じゃなくて)、どのように同じ処理を実現するか、という部分を切り替えるのに有効なわけか。
で、いつどんな時にどのalgorithmを使うかというのを制御するStrategy Classを用意して置いて、そこでうまくやる感じかー。
ああだからifがいくつも並んでいるようなときに使えるかもしれない、という発想になる訳ね。基本的には条件によって処理を切り替える処理を抽象化する、というだけの話だし。
当たり前にやっていることに名前があった感。
Command Pattern
今回はこれで最後。
22.Commandパターン | TECHSCORE(テックスコア)
第22章ではCommandパターンを学びます。あるオブジェクトに対して要求を送るということは、そのオブジェクトのメソッドを呼び出すことと同じです。 そして、メソッドにどのような引数を渡すか、ということによって要求の内容は表現されます。さまざまな要求を送ろうとすると、引数の数や種類を増やさなければなりませんが、 それには限界があります。そこで要求自体をオブジェクトにしてしまい、そのオブジェクトを引数に渡すようにします。それがCommandパターンです。
引数にargsとかkwargsとかいれてobjectを投げるような考え方のこと?
Commandパターンは、実行可能なアクション(コマンド)をオブジェクトとして扱い、コマンドの詳細をカプセル化するパターンです。コマンドの追加や削除に対して柔軟になります。
どちらかというと関数pointerで渡したりcallbackで渡したりする処理の方が近い考えっぽい。
で、Command Patternというのは何を狙ってそんなことをしようと思ったの?
Commandパターンが有効に働く場面
- UNDO、ログの記録、トランザクションをサポートしたいとき
- 非同期でアクションを実行したい場合。キューなどに入れて異なるタイミングで実行する
- イベントとアクションを分離したい場合。Webアプリケーションの作成時に利用
ああやっぱりそういう時に使いたいのね。
というかこの手のpatternってたぶん実際にあったものに対して付けられた分類名っぽいな。言語の品詞分類とか文法とかと同じ香りがする。Patternと名乗っているけどこれ実質はCluster Labelだ。(いやこれを使っている人からすればPatternにしか見えないのはわかるんだけど思考回路が違う……)
Strategy Patternとも似ているような気がするけど、言ってしまえば抽象化って全部そういうものだよね、とも言う。
違うのは粒度。Strategy PatternはAlgorithmという粒度で抽象化して選択できるようにしているけれど、Command Patternはmethod単位の粒度で抽象化している。
今見る範囲ではそれだけの差だと思う。
まとめ
- Singleton Pattern => Program中で唯一のinstanceであることを保証する仕組み
- Visitor Pattern => 1つのClassからData Structureを残してLogicをVisitor Classとして別のClassに抽象化する実装
- Strategy Pattern => algorithm単位の抽象化と環境に合わせた選択機構
- Command Pattern => method単位の抽象化
こんな感じかなあ。