ブログ 約6分

GRASP原則:Irrlicht 3Dエンジンの探究

Share this article
GRASP原則:Irrlicht 3Dエンジンの探究

デザインパターンとは、ソフトウェア設計において、特定のコンテキストでよく発生する問題に対する一般的で再利用可能なソリューションです。パターンは、プログラマーがアプリケーションやシステムを設計する際に一般的な問題を解決するために使用できる、形式化されたベストプラクティスです。

「Gang of Four」のパターンがおそらく最も有名です。しかし、開発者の間ではあまり知られていない基本的な設計原則があります。General Responsibility Assignment Software Principles、略してGRASPです。

Wikipediaの定義は次のとおりです。

一般的な責務割り当てソフトウェアパターン (または 原則)、略して GRASPは、オブジェクト指向設計においてクラスやオブジェクトに責務を割り当てるためのガイドラインで構成されています。GRASPで使用されるさまざまなパターンと原則は、コントローラー、クリエイター、インダイレクション、情報エキスパート、高凝集性、低結合、ポリモーフィズム、保護されたバリエーション、純粋な虚構です。これらすべてのパターンは何らかのソフトウェアの問題に答えるものであり、これらの問題はほぼすべてのソフトウェア開発プロジェクトに共通しています。これらの手法は、新しい作業方法を作り出すために発明されたのではなく、オブジェクト指向設計における古くからの実証済みのプログラミング原則をよりよく文書化し標準化するために考案されました。

Irrlicht は、多くのGRASP原則を使用している3Dエンジンライブラリです。この種のパターンを使用する利点を見ていきましょう。

クリエイター(Creator)

オブジェクトの作成は、オブジェクト指向システムで最も一般的な活動の一つです。どのクラスがオブジェクトの作成に責任を持つかを決定することは、特定のクラスのオブジェクト間の関係の基本的な側面です。例としてGUIスキンクラスを取り上げ、Irrlichtライブラリ内のどこで作成されているかを見てみましょう。そのために、次のCQLinqクエリを実行できます。

SELECT METHODS WHERE DepthOfCreateA “irr.gui.CGUISkin” == 1

CGUIEnvironmentはCGUISkinインスタンスを作成する唯一のクラスであり、CGUIButtonを除くほぼすべてのGUI要素はCGUIEnvironmentクラスによって作成されます。

SELECT METHODS WHERE DepthOfCreateA “irr.gui.CGUIButton” == 1

ご覧のとおり、CGUIButtonは3つの異なる場所で作成されています。他のすべてのGUIクラスと同様に、コードをリファクタリングして作成の責務をCGUIEnvironmentクラスに委譲する方が良いかもしれません。

コントローラー(Controller)

The コントローラー パターンは、システムイベントを処理する責務を、システム全体またはユースケースシナリオを表す非UIクラスに割り当てます。コントローラーオブジェクトは、システムイベントを受信または処理する責任を持つ、非ユーザーインターフェースオブジェクトです。

ユースケースコントローラーは、ユースケースの すべての システムイベントを処理するために使用すべきであり、複数のユースケースに使用できます(例えば、 ユーザーの作成 と ユーザーの削除というユースケースでは、2つの別々のユースケースコントローラーの代わりに、単一の UserControllerを持つことができます)。

GUI要素のコントローラーを見てみましょう。少なくともイベント処理を管理する必要があり、この処理はCGUIEnvironment::OnEventによって実行されます。

OnEventによって使用されるメソッドを見てみましょう。

SELECT METHODS WHERE IsUsedBy “irr.gui.CGUIEnvironment.OnEvent(constSEvent&)”

発生したイベントは、IEventReceiver抽象クラスを実装するクラスによって処理されます。どのクラスがそれを実装しているか見てみましょう。

各GUI要素は、それに関連するイベントを処理します。

CGUIEnvironmentの他の責務は何でしょうか?

前に見たように、このクラスは具象クラスを作成し、イベント処理も管理しています。他の責務があるかどうかを確認するために、このクラスが使用するメソッドを検索できます。

SELECT METHODS WHERE IsDirectlyUsedBy “irr.gui.CGUIEnvironment”

このクラスはまた、irr::io名前空間のいくつかのクラスを使用してXMLファイルを永続化および読み込みます。おそらくこのクラスは多くの責務を持っており、その凝集性に影響を与える可能性がありますが、データを永続化するために必要なすべてのデータを持っているため、まだ許容範囲です。これはGRASPの「情報エキスパート」原則に従っています。

低結合(Low Coupling)

低結合は望ましいものです。なぜなら、アプリケーションのある領域の変更が、アプリケーション全体で必要とする変更を少なくするからです。長期的には、これによりアプリケーションの修正や新機能の追加に伴う多くの時間、労力、コストを節約できる可能性があります。

抽象クラスを使用すると低結合を実現するのに役立ち、次のメトリクスで特定のモジュールの抽象度を評価できます。

A = Na / Nc

ここで: * A = モジュールの抽象度 0は完全に具象的なモジュール、1は完全に抽象的なモジュールです。 * Na = モジュール内の抽象クラスの数。 * Nc = モジュール内の具象クラスの数。

Irrlichtの抽象度は0.1245972で、125の抽象クラスが含まれています。irr::gui名前空間には28の抽象クラスがあり、各GUI要素には同等のインターフェースがあります。

SELECT TYPES FROM NAMESPACES “irr.gui” WHERE IsAbstract

CppDependはDSMを提供しており、この行列を三角化して、強く依存しているクラスを強調する赤い境界に焦点を当て、モジュールを検出できます。

ご覧のとおり、すべての抽象クラスはまとめてグループ化されており、別の名前空間や、場合によっては別のプロジェクトに分離できる可能性があります。抽象クラスを使用して低結合を実現する利点を確認するために、具象クラスCGUISkinを使用しているクラスを検索してみましょう。

SELECT METHODS WHERE IsDirectlyUsing “irr.gui.CGUISkin”

このクラスを直接知っているのは1つのクラスだけです。その作成者です。他の具象クラスは抽象クラスを通じて使用されており、これは疎結合を促進します。

名前空間間の結合はどうでしょうか?

一部の名前空間間には依存関係の循環が存在します。そのような依存関係を持つことは必ずしも問題ではありません。しかし、それを避けることは疎結合を促進します。

名前空間が互いにどのように相互作用しているかを調べることもできます。そのために、「irr」名前空間が使用しているクラスとメソッドを見てみましょう。

SELECT METHODS WHERE IsDirectlyUsedBy “irr”

ご覧のとおり、他の名前空間とのほぼすべての相互作用は抽象クラスを通じて行われていますが、irr::video::CVideoModeListとirr::scene::CMeshBufferは例外です。

irr::video::CVideoModeListへの依存関係の起源を調べてみましょう。そのために、次のCQLinqクエリを実行できます。

SELECT METHODS OUT OF TYPES “irr.video.CVideoModeList” WHERE IsUsing “irr.video.CVideoModeList”

irr::CIrrDeviceWin32クラスがそれを使用しているのは、video::IVideoModeListではなくvideo::CVideoModeListとしてフィールドを宣言しているためです。名前空間間の相互作用を改善するために、リファクタリングを行うことができるかもしれません。

高凝集性(High Cohesion)

単一責任の原則は、クラスは変更する理由を1つだけ持つべきであると述べています。そのようなクラスは凝集性が高いと言われます。高いLCOM値は一般に、凝集性の低いクラスを示します。いくつかのLCOMメトリクスがあります。LCOMは[0-1]の範囲の値を取ります。LCOMHS(HSはHenderson-Sellersの略)は[0-2]の範囲の値を取ります。LCOMHSメトリクスは、凝集性のない型を検出するのにより効率的であるとよく考えられていることに注意してください。1を超えるLCOMHS値は警戒すべきと考えるべきです。

SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10 AND!IsGlobal ORDER BY LCOMHS DESC

凝集性がないと見なされるクラスはごくわずかです。

結論

Irrlichtは、コードベースをモジュール化するために名前空間を使用し、低結合を改善するために抽象クラスを使用しており、理解と保守が非常に容易になっています。設計品質を向上させたい場合に従うべき良い例です。

Share this article