[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends] Re: CADのクラス構造




前橋です。

Shin さん:
>>でも、CADなどの大規模なアプリケーションで、そのシステムの根
>>幹をなすようなデータ構造に対し、draw()なんてもんをくっつけて、
>>本当にいいのでしょうか?
>付けても切り離してもよいと思います.
...
>実装ですか?draw()はインターフェイスですので特定の具象クラスの実装
>が変わっても(コンパイルというレベルでは)何も影響は無いですよね.
>インターフェイスが変わった場合ということですね.

あ、そういえばそうでした。Shapeのdraw()に変化がない限り、そ
のサブクラスのdraw()をいじっても、コンパイルは必要ないことが
多そうですね(ダウンキャストして直接サブクラスを見てたりしな
ければ)。

でも、インタフェースが変わった場合や、(draw()以外のメソッド
を含めて)増えたり減ったりする場合のことを考えると、やっぱり
問題です。

>どんな形状でも二次元空間に表現出来る機能を持たせるべきと判断した
>らくっつけると思います.
>データベースに登録されるのはオブジェクトであって、クラスではない
>ですので、deserializeしたオブジェクトのdraw()を呼ぶ呼ばないは利用
>者の自由ですね.

ええと、どんな形状でも、こっちのアプリ(またはコマンド)では二
次元空間に表現出来る機能が要るけれど、こっちのアプリ(または
コマンド)ではそれは全然使わないかも知れない、という場合につ
いては、「呼ぶ呼ばないは利用者の自由」としてくっつけてしまえ、
というご意見であるということでよろしいでしょうか。

>ただし、ここでさっきの「drawの実装が変わったら」の問題が出る可能
>性がありますね.
>サブクラスも同じようにデータベースに格納するとなると、オブジェク
>トデータベースになると思いますが、その場合シリアライズされたオブ
>ジェクトになりますもんね.
>クラスが再コンパイルされてバージョンが変わったら、を考えると厄介
>です.
>serialversionIDをいじって古いオブジェクトもデシリアライズ可能にす
>るのかなあ?あまり勉強していませんが.

そうですね。私もあまり勉強していませんが、メソッドが減ろうが
増えようが、データメンバが変わらない限り、シリアライズすれば
*基本的には* 同じものが出てくるでしょうから、きっとごまかし
ようは...

でも、クラスファイルが変わっちゃった時点で、古いバージョンで
シリアライズしたものを読むのは、なんだか「気味が悪い」感じが
しませんか?

>こちらですね.上に書いたようにどんな形状でも(toStringみたいな感覚
>で)二次元空間(には限らないが特定の空間)に自分を表現出来た方が良い
>という場合はくっつけますが、その必要性が特に無く、将来的に3次元空
>間に描画する機能などの拡張を考慮する場合は、Shape#draw()は使われ
>なくなる可能性があります.
>その時に(上に書いた事と少し矛盾しますが)全く使われないメソッドの
>ためにclassファイルサイズを食うのは嫌だということであれば、Shape
>のサブクラス群と一対一になるDrawインターフェイスの実装クラスを用
>意することになると思います.
># データベースの格納サイズは得に変わらないので別に残っててもいい
># 気はしますが.

ファイルサイズはともかくとして、このアプリ(またはコマンド)で
しか使わないメソッド、あのアプリ(またはコマンド)でしか使わな
いメソッドを、主要なクラスにべたべた取り込んでいくのは、概念
的に美しくないように思うのです。

データ構造の整合性を維持するために絶対不可欠なメソッドなら、
Shapeみたいな所に入っていても文句はないんですけれども。

Shapeはデータベースに格納されるわけですけど、データベースといえば、

・大昔のアプリケーションは、それぞれ勝手な形式のファイルにデー
  タを保管していた。それらのファイルの間には、重複した情報も
  あったりして、管理が大変だった。
・そこで、データベースに情報を全部置いて、アプリはそれを参照・
  操作するようにした。

というものだったと思うんですが、その場合、データベースに入っ
ているモノは、各アプリから独立でなければならないのでは?

そうすると、データベースに入っているモノは、外部から参照され
たり操作されたりする客体に過ぎなくなるわけで、よって各データ
が主体的に動くオブジェクト指向とは概念が真っ向から対立してそ
うで、するってえと「オブジェクト指向データベース」というのは、
名前からして矛盾している存在なような気もしないでもない...

データベースにはメソッドは「実際には」格納されないわけですが、
概念としてはやっぱりメソッドはオブジェクトにくっついているも
のだと思いますし。

だからといって、drawをShape以外の所に置いてしまうと、

・Shapeの各サブクラスのデータメンバは、全部publicにするかア
  クセサを付けるかして「まる見え」にしなきゃいけない。
・いざ描画するときには、長〜いelse ifの連なりで、いちいち
  instanceofでクラスを調べるの?

ということになっちゃいます。これはこれで悲し過ぎます。特にふたつめ。

># ShapeにはDrawインターフェイスの実装クラスを返すfactory methodを
># 用意しておけばよいのでは無いでしょうか.
># そして、描画処理では
># shape.getDraw().draw2DScreen(....);
># shape.getDraw().draw3DScreen(....);等
>Drawインターフェイスに新しい空間への描画機能が追加されるなどの拡
>張を施しても、逆に機能を削除しても、Shapeには影響は無いですね.
>でも、インターフェイスが変われば、Shapeのサブクラス数に相当する
>Drawの実装クラスの変更/再コンパイルは結局必要ですが.

勉強になります。

これだと、DrawをShapeと独立して自由にいじれますが、

「そもそも描画するかどうかもわからんのにShapeにDrawを入れるべきか」

という点からすると...

これが良いと思うわけでもないのですが、私の案としては、

・ShapeRunTimeというabstractクラスを作って、そのインスタンス
  をShapeインスタンスが保持するようにする。
・ShapeRunTimeを継承して、ShapeRunTimeForDrawerを作り、
  「drawするアプリケーション」では、Shapeにそいつをくっつけ
  ておく。他のことするアプリケーションは、それぞれ
  ShapeRunTimeForXXXXを作る。
・「drawするアプリケーション」は、ShapeRunTimeをダウンキャス
  トして使う(ここが美しくない)。
・ShapeRunTimeForDrawerには、abstractなメソッドとして、
  draw()を入れておく。ShapeRunTimeForDrawerを継承して
  LineRunTimeForDrawerなどを作る。draw()の実装はそこに書く。

こんな感じ... かなあ。

------------------------------------------------------------
  前橋 和弥                             maebashi@xxxxxxxxxx
  中部ソフトエンジニアリング(株)
    〒450 名古屋市中村区名駅4-10-25(名駅IMAIビル 5F)
    Tel:(052)583-4511(代) 内線 252 Fax:(052)583-4566
------------------------------------------------------------