サブシステムとは、コンポーネントとして独立性の高いパッケージと考えてください。コンポーネントとはソフトウェアの部品です。部品は、必ずインターフェイスが決められています。例えば電子部品などでは、必要な電源電圧、信号線の役割などが部品ごとに決められています。
この部品のインターフェイスをできるだけ多くの電子製品から利用してもらえるようにインターフェイスを共通化すると、その部品はいろいろなところに使えます。また、部品は、内部がどうなっているかを知らなくても利用することができます。電圧を5V供給する必要があっても、部品内部でどのように使われているかを知る必要はありません。部品の内部はブラックボックスで、あくまでもインターフェイスが分かっていればいいのです。
ソフトウェア部品もできるだけ共通に利用されるようなインターフェイスを決めると再利用性が高まります。また、ソフトウェア部品をブラックボックスのように、内部を知らなくても利用することができれば、生産性、保守性が向上します。サブシステムとはインターフェイスの標準化とブラックボックス化により、ソフトウェアをコンポーネント化(部品化)するための技法です。
サブシステムもクラスと同じように責務を持ちます。クラスの責務と比較すると大きな責務です。そして、サブシステムはパッケージと同じように内部に複数のクラスを持っています。それらのクラスは、サブシステムの責務を実現します。このようにサブシステムは、クラスとパッケージの両方の性質を持っています。
サブシステムは、内部のクラスを隠蔽(カプセル化)し、インターフェイスを外部に公開します。サブシステムの実態は、パッケージとインターフェイスです。ある責務を実現するクラスをパッケージにまとめ、クライアントに公開したい機能をインターフェイスとして定義し、パッケージ自体をコンポーネント(部品)のように扱えるようにしたものがサブシステムです。
サブシステムには、デザインパターンのFacadeパターンが適用できます。Facadeパターンでサブシステムの入り口を1カ所にまとめ、内部クラスの個々のクラスの操作をサブシステムとしての操作にまとめます(図1)。
このとき、定義するインターフェイスは、いろいろなクライアントから利用できるようにすることが必要です。サブシステムは、普遍的な構造の責務を持っています。普遍的な構造は、固有な構造のサービス(ユースケース)から利用されます。そのため、サブシステムはいろいろなサービスから利用することができるように標準的なインターフェイスを定義しなければなりません。
そして、Facadeクラス以外の内部のクラスは、パッケージのアクセス制御を利用して外部からはアクセスを制限します。例えば、継承は許すが外部のクラスとの関連や依存は許さないなどです。これによりサブシステムをブラックボックスとすることができます。
サブシステムを設計する場合はコンポーネント化を意識する必要があります。上流工程では、ユースケース分析や概念モデリングを通して、普遍的な構造や固有な構造を分析・設計していくとお話ししました。普遍的な構造は、コンポーネントで構成されるように設計します。つまり、普遍的な構造は、コンポーネントであるサブシステムで構築され、固有な構造であるユースケースに基づくクラスからサブシステムが利用されます。
どのようなサブシステムが存在するかは概念モデルを洗練する段階で少しずつ洗い出していきます。概念モデルで最初に洗い出されるクラスは、どちらかというとサブシステムに近いものかもしれません。例えば、概念クラスである会員なども、複雑な管理が必要になれば複数のクラスで責務を実現することになるので、会員管理サブシステムとなります。
ユースケースからコンポーネントを利用すると、コンポーネント単位での設計になるので構造がシンプルになります。これは、ユースケースが追加になった場合など、クラスの複雑な使い方を知らなくてもよいので便利です。サブシステム化されていない貸出ユースケースでは、図2のように貸出コントローラから、貸出クラス、会員クラス、商品クラスなどのシーケンスの流れを考えなければなりません。
それに対し、図3では貸出管理サブシステムに対して貸出コントローラは操作を行えばよく、シンプルな構造になります。会員クラスや商品クラス、タイトルクラスなどの使い方を知らなくても貸出管理サブシステムの使い方を知っていれば設計できます。
また、分析設計をサブシステム単位に行うことができます。つまり会員管理サブシステムは、外部とのインターフェイスを決めれば、内部の設計は独立して行うことができます。これにより並行開発が可能になり開発効率が向上します。サブシステムの内部は、独自にシナリオによる業務分析やクラス設計を行うことができます。
サブシステムを利用することでコンポーネントベースの開発が可能になります。このようにサブシステムを利用することにより、システムの構造をシンプルにし理解しやすくできます。
サブシステムを利用する利点としては、次のようなことが挙げられます。
インターフェイスの利用やブラックボックス化により、予想されないような変更に強くなります。サブシステムは、外部のクラス等の変化からの影響を受けにくくし、内部の変化がクライアントに影響することを防ぎます。
サブシステムにおける、クライアントとの接点はインターフェイスとFacadeクラスです。クライアントはインターフェイスを経由してFacadeクラスの操作を利用します。クライアントはインターフェイスを経由して操作を利用するので、サブシステム内部のクラスに変更があっても影響を受けません。
また、Facadeクラスで、個々のクラスの操作ではなく、サブシステムとして操作をまとめているので、個々の内部クラスの変更の影響は、Facadeクラスでも吸収できます(インターフェイスが変更になるような変更は駄目ですが)。
内部に存在するクラスと外部に存在するクラスやサブシステムに依存関係がある場合は、できるだけ依存関係の少ない関係にします。例えば、貸出管理サブクラスの貸出クラスは、会員管理サブシステムに依存関係があります。貸出クラスは会員が存在するかチェックする必要があるからです。
このようなとき依存関係を、関連や集約、コンポジションから依存、汎化などの依存関係が弱い関連に直すことにより、サブシステムの外部からの影響は少なくなります。
サブシステムの操作は、クラス単体の操作より、高機能な操作を提供することが可能となります。なぜなら、複数のクラスにまたがる複雑な操作を1つの操作にまとめることがFacadeクラスでは可能だからです。
これは内部的な操作をクライアントが知らなくてもよくなり、そのため必要最小限の操作のみ利用すればよいので再利用性が高くなります。
サブシステムのインターフェイスが同じであるなら、ほかのサブシステムと交換が可能になります。
サブシステム単位に機能を分析・設計を行い、インターフェイスやブラックボックス化することにより、コンポーネント単位での開発が可能となり、並行開発が可能となります。
システムを設計する際に、コンポーネントという抽象化レベルの高い概念から分析することができ、システム全体の理解が容易になります。
このように、サブシステムはソフトウェアのコンポーネント化を促進します。ただ、コンポーネント化は簡単ではありません。それはクラス間の依存関係を整理しないでサブシステムにまとめても、内部のクラスがサブシステム外のクラスに依存してしまうためです。内部のクラスが外部のクラスを利用する場合には、より依存度の少ない方法で利用するように、依存関係を整理する必要があります。
パッケージはクラスを整理整頓し利用しやすくまとめます。整理の基準は、決まりがあるわけではありませんが、「レベルが同じもの」「機能的に似ているもの」 「目的が同じもの」などが考えられます。 また、サブシステムは、インターフェイスとFacadeパターンを利用することにより、 内部を隠蔽し、機能を整理してコンポーネントとします。このとき、サブシステム内部の強度(クラス間の結びつき)が高く、サブシステム間の結合度(外部との結びつきの度合い)が低くなるように整理整頓します。このようにパッケージやサブシステムを使用するとコンポーネント化が促進され、保守性や拡張性を高めることができます。
今回は、コンポーネント化という視点でパッケージやサブシステムについてお話しました。次回は、今回の続きでパッケージやサブシステムにおける依存関係の整理をどのように考えるか、そして予想される変更に対応するための仕組みであるホットスポットについてお話したいと思います。
Copyright © ITmedia, Inc. All Rights Reserved.