Home > あいそるニュース > よく使うデザインパターンとは
よく使うデザインパターンとは
2008-11-05 08:47
GoFによるデザインパターンはオブジェクト指向の学習教材としては非常に有効だと思いますが、 実際の業務アプリケーションの開発現場ではどのくらい使用されているのでしょうか。
私自身、デザインパターンを使うことでレベルの高いソースコードだと思われたいという、 あまりにも稚拙な理由でよく使っていた時期もありました。誰もが陥りやすい若さゆえの過ちです。
今はGoFのデザインパターン以外にも、たくさんのパターンが存在しているようですが、 少なくとも私の経験の中でGoFの23のパターンのうち、今でもよく使うものを選んでみました。
私はJavaによる業務Webアプリケーション及びそのフレームワークの開発者なので、制御系のシステム開発は経験がありません。 それ故、使用するパターンが業務Webアプリケーション開発向けに偏っていると思います。 あくまでも私(筆者)の独断と偏見ですのでご了承ください。
よく使う
- Template Methodパターン
- Iteratorパターン
- Singletonパターン
- Flyweightパターン
たまに使う
- Observerパターン
- Proxyパターン
見栄を張らずに言うと、未だによく使う・たまに使うパターンは上記の6種類くらいです。 どれもこれもデザインパターンの初級レベルのものばかりです。
Template Method パターン
私がフレームワークを開発する際には、フレームワークとビジネスロジックとの関係は必ずこのパターンを使用します。 StrutsのActionクラスもこのパターンを適用していますので、よく見かけるパターンだと思います。
場合によっては私はサブクラスが実装すべきスーパークラスのメソッドをabstractにしない場合があります。
こうすることにより、スーパークラスにデフォルトの振る舞いを記述できるからです。
例えば、右図のようにスーパークラスにmethod1,method2,method3が定義されており、 それぞれデフォルトの振る舞いが記述されていれば、サブクラスではデフォルトの振る舞いと異なるメソッドのみ オーバーライドすればよいことになります。
具体的な例を挙げますと、業務アプリケーションで様々な形式のデータファイルを読み込ませる機能があったとします。 ファイルの読み込みは基本的には似たような処理が多いですが、ファイルの形式によって部分的に異なる所もあります。 このような場合は、サブクラスにてデフォルトと異なる部分のみをオーバーライドでカスタマイズすることにより対応できるわけです。
Iterator パターン
ある共通メソッドの戻り値として複数の値を順番付きで返す必要がある場合、Listを使うのが最もシンプルだと思います。 無理してIteratorパターンを使用する必要はありません。
しかし、例えばその戻り値のListの要素が数万~数十万件になる可能性がある場合はListで返すとなると
それだけ要素となるオブジェクトのインスタンスを一気に生成することになりますので、
メモリが溢れる(Out Of Memroy)可能性があります。
そのような場合はIteratorパターンを使用し、次の要素が要求される度にその都度インスタンスを生成するようにします。
また、戻り値の要素1つ生成するのに非常に時間がかかる場合で、且つその戻り値を利用するクライアントは 各要素を一気に使用しない場合も、Iteratorパターンが効果的だと思います。
Singleton パターン
Javaの場合、教科書通りgetInstance()メソッドにsynchronizedを使用して記述しているコードを たまに見かけますが、synchronizedはコストが高いのでstatic変数を定義してそれを利用するのが最もシンプルだと思います。
ただしsynchronizedを使用しないとした場合、そのstatic変数となるオブジェクトに初期化ロジックが必要な場合は タイミングに悩みます。単純にstaticフィールドでnewしたりstaticイニシャライザを使用すると そこでエラーが発生した場合はキャッチできないからです。
public class Singleton {
private static final Singleton singleton = new Singleton();
上記の場合インスタンス生成時にエラーが発生した場合はキャッチできない。
下記の場合も同様にstaticイニシャライザ内でエラーが発生した場合はキャッチできない。
private static Singleton singleton = null;
static{
singleton = new Singleton();
・・・
}
}
結局Singletonとしたいオブジェクトを生成する際にエラーが発生する可能性がある場合(例えばDBにアクセスする等)は、
別途initializeというメソッドを用意し、Webアプリケーション起動時のリスナーでそれを呼び出すことにより
エラー発生時はExceptionをキャッチして異常を検知するようにしています。
※initializeメソッドはprotected等しかるべきスコープにする必要があります。
もっとスマートな方法はないかといつも悩みます。
ちなみにSingletonという考え方は、Singletonパターンを学ぶ前からやっていた事ですが、
コンストラクタをprivateスコープにするという発想はこれで覚えました。
Singletonパターンだけではなく、インスタンスを生成する必要の無いstaticメソッドだけを定義した共通メソッドだけのクラスも
私はコンストラクタをよくprivateスコープにしています。
Flyweight パターン
ファイル等に定義してあるアプリケーション独自の設定情報の管理はFlyweightをよく使用します。 Flyweightというとカッコよく聞こえますが、要は単なるキャッシュです。
Observerパターン
フレームワークを開発していると、たまにXXXXListenerというインタフェースでクライアントに通知をする仕組みを考えますが これがObserverパターンになります。
よく言われているようにobserverとは「観察者」という意味ですが、 実際このパターンでのObserverクラスは「観察者」ではなく「通知」を受けるクラスになります。名前から入ると理解を誤りますので注意が必要です。
Proxyパターン
先に述べたIteratorパターンと同様に、生成コストが高いがそのインスタンスをクライアントがすぐに使用することが無い場合は、 Proxyパターンを適用する事があります。
リソース削減・パフォーマンス向上のパターンが多い
と、ここ最近自分が開発したシステムをアレコレ思い出してみたのですが、よく使っているパターンと言えばこんなもんです。
シンプルで分かり易いものが多いです。
保険系システムに限ったことではないと思いますが、システムが扱うデータ件数が大量であり、また関連するテーブルが多くなってきている為か、よく見ると消費リソースを抑えたりパフォーマンスを上げる為のパターンを多用しているということに気付きました。
デザインパターンではもっと複雑で難易度が高くかっこいいパターンが沢山あるものの、
ソースコードに格好つけて自己満足する為に使用することが目的ではありません。
適材適所に適用することが大事です。
そんなことを心に留めながらいくつもシステムを作ってきましたが、
ここ数年で上記以外に実際にデザインパターンを適用する機会はあまり無かったと思います。
といってもそれはあくまでも私(筆者)の経験と発想力がまだまだ未熟だからからかもしれません。
でも、Visitorパターンは一生使わないだろうと思います。
Posted by T.S
