【デザインパターン】ビルダーパターン
研究のスライド作ってたら26時で焦って書き始めました。
続きを読む【デザインパターン】コンパウンドパターン【MVC】
家の中のコバエをすべて駆逐したい。
続きを読む【デザインパターン】コンパウンドパターン【事前学習編2】
前回までの確認
【デザインパターン】コンパウンドパターン【事前学習編1】 - datchの日記
鴨シミュレータを作成するために今まで習った様々なデザインパターンを適用してきました。
- Adapter
- Decorator
- Factory (AbstractFactory)
事前学習
前回の最後はAbstractFactoryパターンを適用し、鴨の鳴き声のカウンティングを行うクラスの生成をFactoryに集中させました。
これによって毎回DecoratorのQuackCounterクラスの生成を記述する必要がなくなり、クラスの生成に関する変更に対して柔軟にすることが出来ます。
Iterator/Compositeパターン
現在のシミュレータの以下のコードを見て下さい。
Quackable mallardDuck = duckFactory.createMallardDuck(); Quackable redheadDuck = duckFactory.createRedheadDuck(); Quackable ducCallk = duckFactory.createDuckCall(); Quackable gooseDuck = duckFactory.createRubberDuck(); Quackable gooseDuck = new GooseAdapter(new Goose()); simulate(mallardDuck); simulate(redheadDuck); simulate(duckCall); simulate(rubberDuck); simulate(gooseDuck);
インスタンスの生成に関しては処理を一元化することが出来ましたが、
生成とシミュレーションの処理が繰り返しで行われており、これではクラスが増えた時に面倒です。
ではここでCompositeデザインパターンを使ってみましょう。
Compositeパターンはオブジェクトの集合を単体のオブジェクトとして扱うことが可能にするパターンです。
public class Flockimplements Quackable{ ArrayList quackers = new ArrayList(); public void add(Quackable quacker){ quackers.add(quacker); } public void quack(){ Iterator iterator = quackers.iterator(); while(iterator.hasNext()){ Quackable quacker = (Quackable)iterator.next(); quacker.quack(); } } }
Compositeパターンを使用したクラスを作成しました。
後はこれをDuckSimulatorクラスに適用していきます。
public class DuckSimulator{ void simulate(AbstractDuckFactory duckFactory){ Quackable mallardDuck = duckFactory.createMallardDuck(); Quackable redheadDuck = duckFactory.createRedheadDuck(); Quackable ducCallk = duckFactory.createDuckCall(); Quackable gooseDuck = duckFactory.createRubberDuck(); Quackable gooseDuck = new GooseAdapter(new Goose()); Flock flockOfDucks = new Flock(); // 様々な鴨を管理するCompositeパターンです flockOfDucks.add(redheadDuck); flockOfDucks.add(duckCall); flockOfDucks.add(rubberDuck); flockOfDucks.add(gooseDuck); // Adaptorを通したものでも同様に処理が可能! Flock flockOfMallards = new Flock(); // これは小さなマガモの手段を管理するCompositeです Quackable mallardOne = duckFactory.createMallardDuck(); Quackable mallardTwo = duckFactory.createMallardDuck(); Quackable mallardThree = duckFactory.createMallardDuck(); Quackable mallardFour = duckFactory.createMallardDuck(); flockOfMallards.add(mallardOne); flockOfMallards.add(mallardTwo); flockOfMallards.add(mallardThree); flockOfMallards.add(mallardFour); flockOfDucks.add(flockOfMallards); // 覚えていますか?Compositeパターンは自身に同様のCompositeを追加することが出来ます! simulate(flockOfDucks); // これは様々な鴨の鳴くだけでなく、マガモの集団も鳴きます simulate(flockOfDucks); // もちろん、同様の呼び出しでマガモの集団だけを鳴かせることも出来ます } }
これにより、鴨のシミュレーションが呼び出し一つで行えるようになりました。
追加の記述が面倒、これなら普通にsimulate()を複数書いたほうが短くないか?という疑問もあるでしょう。
しかし、この鴨の呼び出しが何度も行われるようなケースではCompositeパターンを使うことでもコードの記述量も減り、使いやすいコードにすることが出来るでしょう。
Observerパターン
どうやら新しい要求が来たようで、逆に個々の鴨も管理の対象に置きたいようで、鴨が鳴いた瞬間を知りたいそうです。
とある動作をした時に、その動作をしたことを知るパターン。
そう、ここでObserverパターンの使い所です。
まずはObserverableという監視対象に適応したいインターフェースを作成します。
public interface QuackObservable{ public void registerObserver(Observer observer); public void notifyObservers(); }
次にQuackableにこのインターフェースを継承します。*1
public interface Quackable extends QuackObservable { public void quack(); }
QuackableにQuackObservableを追加した事により、Quackableインターフェースを実装しているクラスは、registerObserver()とnotifyObservers()の具体的な処理を記述する必要性が出てきました。
しかし、すべてのクラスに詳細な処理を記述しているのは非常に手間がかかり、処理も重複する可能性があります。
ここでは、Observableというヘルパークラスを作成することにより、他のクラスにコンポジションすることで実際の処理を一度記述するだけでよくなります。
では、実際にObservableクラスを見て行きましょう。
public class Observable implements QuackObservable { ArrayList<Observer> observers = new ArrayList<Observer>(); QuackObservable duck; public Observable(QuackObservable duck) { this.duck = duck; } // 通知するオブザーバを登録する public void registerObserver(Observer observer) { observers.add(observer); } // オブザーバに通知するための関数 public void notifyObservers() { Iterator<Observer> iterator = observers.iterator(); while (iterator.hasNext()) { Observer observer = iterator.next(); observer.update(duck); } } }
コンストラクタの部分で実体のQuackObservableを保持することで、このクラスに処理を集中させることが出来るのがわかると思います。*2
実際のコードを見て、Observableがどのように使われるか見てみましょう。
public class MallardDuck implements Quackable { Observable observable; public MallardDuck() { observable = new Observable(this); } public void quack() { System.out.println("Quack"); notifyObservers(); } public void registerObserver(Observer observer) { observable.registerObserver(observer); } public void notifyObservers() { observable.notifyObservers(); } } public class Flock implements Quackable { ArrayList<Quackable> ducks = new ArrayList<Quackable>(); public void add(Quackable duck) { ducks.add(duck); } public void quack() { Iterator<Quackable> iterator = ducks.iterator(); while (iterator.hasNext()) { Quackable duck = (Quackable)iterator.next(); duck.quack(); } } public void registerObserver(Observer observer) { Iterator<Quackable> iterator = ducks.iterator(); while (iterator.hasNext()) { Quackable duck = (Quackable)iterator.next(); duck.registerObserver(observer); } } public void notifyObservers() { } }
registerObserver()・notifyObservers()の処理を受け取った時、Observableにその処理を流しているのがわかると思います。
処理を委譲しているんですね。
まだ終わっていません。
今は通知を行う側しか存在しないので、その通知を受け取るObserverクラスを作成します!
public interface Observer { public void update(QuackObservable duck); }
次にこのクラスの具象クラスが必要になるので、Quackologistというクラスを作成します。
このクラスにより、鴨が鳴くと、Observerとしてどの鴨が鳴いたかを知ることが出来るようになります!
public class Quackologist implements Observer { public void update(QuackObservable duck) { System.out.println("Quackologist: " + duck + " just quacked."); } }
さて、Observerが完成したので、実際に鴨シミュレータでどのように動作するかを見てみましょう。
simulate関数の中身を抜粋して書いていきます。
Quackologist quackologist = new Quackologist();
flockOfDucks.registerObserver(quackologist);
simulate(flockOfDucks);
Observerを作ってflockOfDucksに監視者として登録させているだけです。
ここで驚きなのは、flockOfDuckというCompositeに登録するだけですべての鴨を監視できていることです。
Compositeを使わなければ、ここで沢山registerObserverを書かなければいけなかったことを考えると、かなり処理が簡略化しているのが伺えますね!
次回
- Adapter
ガチョウも鴨と同様に扱えるようにした - Decorator
鴨の鳴き声を数えられる機能を追加した - Factory(AbstractFactory)
インスタンスの生成を一元して管理するようにした - Composite
繰り返しの処理をグループ管理した - Observer
処理を監視した
これらのパターンを順々に適応していった。
このような感じでデザインパターンを複雑に組み合わせることで、シンプルなコードが出来上がります!
自分もこんな風にデザインパターンを利用出来るようにしたいですね。
しかし、これはまだCompoundパターンでは無いみたいなのです!
この本で触れるCompoundパターンとは我々、Webエンジニアがよく触るMVCを例にして紹介しています!
次回はMVCについて触れて始めていくよ!
ブログを一年間振り返ってみて
どうも、急用があり現在は実家に帰省している最中です。
同じ焼き肉メンバーの方々が一年間の振り返りを行っているので、自分も振り返りを行っていきたいと思います。
【デザインパターン】コンパウンドパターン【事前学習編1】
どうも、昨日見事にブログを書き忘れていました。
続きを読む裏開発備忘録
どうも、最近プライベートもやるべき事も中々ホットになってまいりました。
そういえば、ネットワークスペシャリスト試験受けるつもりだったのですが、試験日とプライベートの日程が重なってしまったので、今回は受けられないですね。
ネットワークに関する理解が曖昧だったので、この機に知識を深めたかったのですが。
さて、少し投稿が遅れてしまいましたが、今日は内定者同士でチームに分かれて開発を行っていたことで得られた事とか、裏話的な話をします。