2004年11月24日

Heimdallrで使われているデザインパターン(2/4)

それではHeimdallrにおいてデザインパターンが使われているクラス構成を紹介します。

最初に紹介するのは、Heimdallrのスキン関連のクラス構成です。 ここがHeimdallrにおいてもっともデザインパターンが有効に活用されたところでしょう。

以下にクラス図を示します。
このクラス図は、Heimdallrの本来のクラス構成そのものと完全に一致しているわけではありません。 デザインパターンにあまり関係無い部分は省き、分かり易い様にしてあります。
また、本クラス図を作成したソフトの都合上、CSkin*を返す関数、というのは記述し難かったので、 CSkin*を返す関数もCSkinを返す関数もCSkin&を返す関数も、まとめてCSkinを返す関数として記述してあります。 適当に解釈して下さい。

20041124_designpattern.png

以下、各クラスを順番に説明していきます。

CRankedViewFrame
ビューを管理するクラスです。アプリケーション起動時に、ビューの数だけインスタンスが作成されます。 MFCのCFrameWndから派生したクラスでもあります。
CSkinManager
CSkinを管理するクラスです。スキンIDからCSkinのインスタンスを返すGetSkinメンバ関数を持っています。
CSkin
スキンファイルの各種データを管理するクラスの基底となる抽象クラスです。 スキンに対応するCSkinContextを生成するGetContext抽象メンバ関数を持っています。
CSimpleSkin
シンプルスキンを管理するクラスです。 アプリケーション起動時に、シンプルスキンファイルと同じ数だけインスタンスが作成されます。
CTransparentSkin
透明スキンを管理するクラスです。 CSimpleSkinと同様に、透明スキンファイルと同じ数だけインスタンスが作成されます。
CPaintSkin
ペイントスキンを管理するクラスです。 本クラスもCSimpleSkinと同様に、ペイントスキンファイルと同じ数だけインスタンスが作成されます。
CSkinContext
CRankedViewFrameの描画を行うクラスの基底となる抽象クラスです。 描画を行うためのDraw抽象メンバ関数をはじめ、マウスが動いたときに呼び出されるOnMouseMove、OnMouseLeaveメンバ関数や、 ビューのサイズや位置が変わったときにに呼び出されるOnSize、OnMoveメンバ関数、更新アイコンの表示/非表示を切り替えるShowUpdateIconメンバ関数を保持しています。
CSimpleSkinContext
シンプルスキンの描画を行うクラスです。
CTransparentSkinContext
透明スキンの描画を行うクラスです。
CTransparentTextFrame
Heimdallrの透明スキンは、2つのウィンドウを重ねて実現されています。 1つ目のウィンドウはCRankedViewFrameが管理し、そして本クラスが2つめのウィンドウを管理します。
CPaintSkinContext
ペイントスキンの描画を行うクラスです。

以上で説明したクラス群の重要な役割は、 CRankedViewFrameに、CSkinContextクラスのインスタンスを割り当てることです。 この割り当ては、次のように行われます。

  1. CRankedViewFrameが、ビューのスキンIDを元にCSkinManagerのGetSkinを呼び出して、CSkinクラスのインスタンスを取得します。
  2. CRankedViewFrameが、CSkinクラスのGetContextを呼び出して、CSkinContextのインスタンスを取得します。

本クラス構成において、以下の2つのデザインパターンが使われています。

Abstract Factoryパターン
CRankedViewFrameが、CSkinクラスのGetContextを呼び出して、CSkinContextのインスタンスを取得するところに使われます。
Abstract Factoryパターンの各クラスに対応するクラスは以下の通りです。
Clientクラス
CRankedViewFrame
AbstractFactoryクラス
CSkin
ConcreateFactoryクラス
CSimpleSkin、CTransparentSkin、CPaintSkin
AbstractProductクラス
CSkinContext
ConcreateProductクラス
CSimpleSkinContext、CTransparentSkinContext、CPaintSkinContext
Strategyパターン
CRankedViewFrameの描画処理に使われます。
Stratectパターンの各クラスに対応するクラスは以下の通りです。
Contextクラス
CRankedViewFrame
Strategyクラス
CSkinContext
ConcreateStrategyクラス
CSimpleSkinContext、CTransparentSkinContext、CPaintSkinContext

こうしてデザインパターンを使うことにより、いくつかのメリットがありました。

1つ目のメリットは、スキンの種類を簡単に増やすことができたことです。
デザインパターンを使う以上、このメリットが得られるのは当然です。 透明スキン、ペイントスキンを追加するときに既にこのメリットを享受できましたし、 今後スキンの種類を増やすときにも享受できるでしょう。

2つ目のメリットは、透明スキンのWin9x対応が簡単にできたことです。
Heimdallrでは、透明スキンを実現するためにレイヤード ウィンドウというWin2000以降で追加された機能を使用しているため、Win9xでは透明スキンが実現ません。 そこで、CTransparentSkinクラスのGetContext関数では、OSのバージョンを取得し、Ver.4(Win9x)であればCSimpleSkinContextインスタンスを生成し、Ver.5(Win2000)以降であればCTransparentSkinContextインスタンスを生成するようにしました。 こうしたことにより、CTransparentSkinContextクラスの実装及びテストにおいて、Win9xを一切考慮する必要が無くなり、実装もテストも楽でした。

3つ目のメリットは、重たいスキンやメモリを大量に使うスキンが、他のスキンに影響を与えないように簡単にできたことです。
透明スキンは、レイヤードウィンドウという重たい機能を使う上、CTransparentTextFrameを使ってウィンドウを2枚使っています。しかし、透明スキンを使わなければ、CTransparentSkinContextインスタンスは生成されないため、いくら透明スキンが重たくても他のスキンを使っていれば影響がありません。
また、ペイントスキンは、画像データを保持するためメモリを確保します。メモリを確保するのはCPaintSkinContextなので、ペイントスキンを使わなければ、CPaintSkinContextインスタンスは生成されず、従って、画像がどれほど大きくてもメモリを無駄に消費することはありません。

以上のように、デザインパターンを使うことにより色々と具体的なメリットがありました。
・・・。ということですが、うーむ。本当ですかねこれ。これらのメリットは、デザインパターンだけから得られたメリットもないでしょうし、分析も甘い気がしますし、本気で信じないで下さいねー。
しかしクラス構成を書いた図だけからそのクラス構成のメリットをしっかりと説明するのって難しいですね・・・。

投稿者 MASATO : 2004年11月24日 00:38 | トラックバック
コメント
コメントする









名前、アドレスを登録しますか?