マイクロソフト日本法人で唯一,Software Architectを名乗る萩原氏がアーキテクトとして知っておくべきことについて解説していく。今回のテーマはオブジェクト指向の課題。Javaのブーム以来,ようやくシステム開発に普通に取り入れられるようになってきたが,それ自体は万能の特効薬ではない。むしろオブジェクト指向ゆえに起こる課題も出てきている。適用範囲や使い方を間違ってはならない。

(本誌)

図1●クラスとインスタンス
オブジェクト指向には,現実世界の「モノ」と「コト」を示す実体である「インスタンス(オブジェクト)」と,それに共通する性質や振る舞いを概念上定義する「クラス(タイプ)」がある。通常人間はこれらを場面ごとに無意識に切り替えて使っている。そのため,オブジェクト指向でモデル化するときに混乱しやすい(本誌)。
図2●コンポーネントに求められること
コンポーネントは外部に置いた構成定義情報(設定ファイル)によって振る舞いをある程度変更可能でなければならない。そうでないとバイナリ形式で配布したコンポーネントを複数の場面に適用できないからだ。またこのことは,コンポーネントの独立性を促す(本誌)。
図3●XML文書とオブジェクトにおけるデータモデルの違い
XML文書では,暗黙のうちに順序関係が定義されている。XMLでは例えば章立てを表現するのに<CHAPTER>~</CHAPTER>というタグで表現する。このとき,先頭から順に章が連続して並んでいることを暗黙のうちに表現している。ところがオブジェクトでこれを表現すると,順序関係が失われてしまう。オブジェクトの属性には,順序という概念がないからだ(本誌)。

 最近ではすっかり,標準的な開発手法として定着してきた感があるオブジェクト指向。だが,その御利益は万能ではない。オブジェクト指向の本質的課題を以下で取り上げ,この主流の技術に潜む危うさを考えてみたい。

 ここで採り上げるテーマは,どれもアーキテクチャを考えるうえで重要なものである。例えば機能を実装するコンポーネントをどう分割するか。そして,このときコンポーネント間の依存関係をどう取り除くのか。これらの課題には,オブジェクト指向だけでは対処しきれない。むしろオブジェクト指向の考えを推し進めすぎると,却って融通の利かないシステムができあがってしまう。

 またオブジェクト指向自体がはらむ問題もある。例えば何をオブジェクトとすべきかという古くて新しい課題や,クラスとインスタンスの識別が難しいといった点である。最近ではXML(eXtensible Markup Language)をデータ形式として使うことが多いが,これとオブジェクト指向は実は相性が悪いといった問題もあるのだ。こういった問題点を踏まえないと,システム全体の設計が破綻したり,後々の変化に対応できない可能性が出てくる。

クラスとインスタンスの識別が難しい

 まずオブジェクト指向自体がもつ問題点を見てみよう。オブジェクト指向の学習初期に,タイプ(クラス)とインスタンス(オブジェクト)の違いに悩んだ経験を持つ人は多いだろう。例えば「このクルマを購入したいのですが」といったときの「クルマ」は,タイプなのか,それともインスタンスなのか(図1[拡大表示] )。

 これが新車ディーラで交わされた言葉であれば,タイプである。新車を購入するときは車種,色,オプションの有無などを指定してクルマを特定する。指定条件に合うクルマであれば在庫のどのクルマであってもよい。しかし中古車ディーラであれば,それは目の前に存在するそのクルマである。これはインスタンスだ。この例でも分かるように,人間はタイプとインスタンスを暗黙のうちに使い分けている。この違いを正確にモデリングするには経験が必要であり,オブジェクト指向が難しいといわれる理由の一つである。

役割の変化を実装しにくい

 オブジェクト指向のモデル実装能力に欠けているものとして挙げられるのが,「役割の変化」と「順序性」である。

 例えば企業では,社員が同時に複数の役割を担ったり,時間の経過とともに別の役割を担うようになる。例えば管理職についている社員がプロジェクト・リーダーとなり,会議の議長になり,実務の特定の担当者になる。また最初は一般社員でも,経験を積むにつれ管理職になり,幹部になるなど役職が変わる。このような役割や役職の変更をオブジェクト指向で実装するのは結構難しい。

 通常オブジェクト指向では,役割をインタフェースを使って表現する。それぞれのクラスは役割に応じた責務を担っている。この責務を対外的に公開したのがインタフェースである。JavaやC#ではインタフェース型を持ち,一つのクラスが複数のインタフェース型を継承できる。これを使えば,複数の役割を表現できる。ところが,一度クラスから生成されたオブジェクトのインタフェース型を追加したり削除したりすることはできない。だから役割の変化を実装するのは難しい。

 これを可能にするには,「Decoratorパターン」などのデザイン・パターンを組み込むか,委譲(delegate)などのオブジェクト連携の技法を凝らすしかない。オブジェクト指向言語が忠実にモデルを実装する能力を備えていないから,このような技法が必要となる。技法は一種の回避策として使われているにすぎないのだが,設計の優劣に影響を与えてしまう。

コンポーネントで変化に対応

 だがその一方で,変化に対応するための技法はますます必要とされる。昨今は迅速に業務要件の変更に対応しなければならない。そのためにはシステムを停止することなくプログラムが変更できるようになってほしい。

 これを実現するのがコンポーネント技術である。構成定義(configuration)だけを編集,変更することで実行制御を可能とするからだ(図2[拡大表示] )。さらに,メモリー上でコードや実行を変更できればなおよい。メタプログラミングなどがこれを実現する。C++などの一部の技術で実用化されているが,まだ広く使われるには至っていない。

 一般にコンポーネントというと,再利用可能なソフトウェア部品だと考える人は多い。しかしそれだけではコンポーネントの特性を完全にとらえたことにはならない。コンポーネントには,自身が保持するオブジェクト(またはオブジェクト群)を制御するパラメータをプロパティで設定するための仕組みが必要だ。そうでないとバイナリ形式でコンポーネントを配布して,いろいろなシステムに組み込んでもらうことができなくなるからだ。またコンポーネントは実行システムに配布するときの保守の単位であり,バージョン管理のためにも有効なものだ。この点でコンポーネントはインスタンスに近い概念である。

 構成定義だけを変更して動作を変える方式は,最近主流になりつつある。構成の定義にXMLを使って記述するものが多い。特にJ2EE(Java2 Enterprise Edition)関連や.NET関連で多用されている。また,業務プロセスの実行を制御するワークフロー・システムや,アプリケーション統合製品でも業務プロセスをXMLで定義するものが多い。

XMLとデータモデルが合致しない

 ところでこのXML,実はオブジェクト指向と相性が悪い。データモデルがうまく合致しないのである。例えば順序性の問題がある。

 オブジェクト指向では,オブジェクトやコンポーネントを作成して処理を実行する。従ってXMLドキュメントをオブジェクトとして取り扱えるようにするには,XMLドキュメントをオブジェクトの形に変換してやらなければならない。XML Schemaなどで書かれたスキーマ情報からクラス定義を生成し,実行時にそのクラスからドキュメントを保持するオブジェクトを生成してXMLで書かれたデータをオブジェクトに読み取る。この操作を「データ・バインディング」と呼ぶ。データ・バインディングした後であれば,ランダムにXMLドキュメントのデータ項目にアクセスできる。

 ただし,XMLドキュメントのオブジェクト表現には,XMLデータモデルとオブジェクト・モデルに意味の違いがあるという問題点が存在する(図3[拡大表示])。XMLは要素間に順序関係の意味を持ち,属性間には順序関係の意味を持たない。例えば,XMLで<chapter>…</chapter>という要素が並ぶ場合,最初の要素から順に第1章,第2章,…という意味がある。一方,オブジェクト・モデルでは,クラスのフィールドに順序関係の意味を持たない。つまりデータを取り込んだ時に意味が失われてしまう。配列やコレクション・クラスなどのオブジェクトを使い,順序関係を表現する方法はあるが,これらは実装上の工夫である。オブジェクト・モデルがモデルとして順序関係の意味を持たないという点において,本質的な問題の解決とはなっていない。