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

[jfriends] Re: データベースに格納するデータオブジェクトに持つ機能(Re: CADのクラス構造)




In article <9909020425.AA28261@xxxxxxxxxx>
Kazuya Maebashi wrote:
>>draw(Shape)というメソッドの実装が一つしかなければそうなりかねませ
>>んね.
>
>こちらはあまりにも悲し過ぎますので。
>
>>>・ShapeRunTimeというabstractクラスを作って、そのインスタンス
>>>  をShapeインスタンスが保持するようにする。
>>>・ShapeRunTimeを継承して、ShapeRunTimeForDrawerを作り、
>>>  「drawするアプリケーション」では、Shapeにそいつをくっつけ
>>>  ておく。他のことするアプリケーションは、それぞれ
>>>  ShapeRunTimeForXXXXを作る。
>>>・「drawするアプリケーション」は、ShapeRunTimeをダウンキャス
>>>  トして使う(ここが美しくない)。
>>>・ShapeRunTimeForDrawerには、abstractなメソッドとして、
>>>  draw()を入れておく。ShapeRunTimeForDrawerを継承して
>>>  LineRunTimeForDrawerなどを作る。draw()の実装はそこに書く。

>たとえば、データ構造をシリアライズしてファイルに格納する場合、
>そのデータフォーマット(つまり、Shapeの構造)が公開されていれば、
>それを利用するアプリケーションは、いろんな会社が競合して開発
>する可能性もあります。そういう場合は、アプリ毎の独立性をなに
>がなんでも確保しなければならないでしょうし。

ShapeサブクラスがShapeRunTimeを知っているわけではなく(データベー
スから取り出してから外から付けるとのことなので)、各組織がそこの独
自の実装を付けるわけですね.
その場合、
In article <37cdd7be.3692.87cced020f2c6377@xxxxxxxxxx>
Shin wrote:
>    :
>  otherYYYY(shape);                     // 特殊な操作の場合
>    :
と前橋さん案は同じことかと思います.

まず、LineRunTimeForDrawer等をShapeのサブクラスたちに関連付ける処
理が必要なわけですが、これを行うには結局、
if (shape instanceof Line) {
  shape.runtime = new LineRunTimeForDrawer();
} else if () {
}
みたいな事が必要になってしまいます.

で、Shapeにメンバを持つ形だとその後Drawerを使う時に、

(LineRunTimeForDrawer)(shape.runtime).draw();

なんてしないといけないので、それなら、
アプリケーション側でShapeRuntimeForDrawerを保持して、

if (shape instanceof Line) {
  drawer = new LineRunTimeForDrawer(shape);
} else if () {
}
  :
drawer.draw();

の方がまし、となりますが、これだとアプリケーション側で扱うShapeオ
ブジェクトの数だけDrawerオブジェクトを管理出来なければならないの
で、管理することをあきらめて、

draw(shape) {
  if (shape instanceof Line) {
    new LineRunTimeForDrawer(shape).draw();
    // または、
    // drawLine(shape);※
  } else if () {
    :
  }
    :
}

としてしまえばいい.
「これだと使い捨てオブジェクトが嫌だから※の方を使う」とまあおん
なじようなものかな?(強引だ)

これはShapeがデータクラスと割り切った設計(というか独自の実装を埋
め込むわけにいかないのでそうするしかない局面)の場合です.

>で、Shapeのインスタンスを生成(またはデシリアライズ)するとき
>に、アプリケーションに応じて必要なShapeRunTimeを生成して、そ
>こにくっつけるわけです。
>
>ついでに、ShapeRunTimeは、インタフェースではなくてクラスです。
>実行時のみに必要なデータメンバの格納場所にもするためです。
>その場合、ShapeRunTime共通のデータもあるでしょうし、Drawer専
>用のものなら、ShapeRunTimeForDrawerに突っ込めばいいのです。

利用者は「ShapeRunTimeというクラスをサブクラス化して、独自の実装
を書き、Shapeに実行時に自分で設定して、narrowing castして機能を呼
び出す」という約束を守れるのでしょうか?
別の観点から見て、ShapeRunTimeには実行時のみ使える基本機能も持た
せることが考えられますよね.
それと同程度にdraw()インターフェイスの必要性があれば、
ShapeRunTime#draw()という(抽象)インターフェイスも書いておけば、
narrowing cast無しで呼び出せます.

>>私は、こういうのを用意して、
>>
>>interface ShapeFunction {
>>	public void draw2D();
>>	public void draw3D();
>>	public void otherXXXX();//その他の汎用的そうな機能?
>>}
>...
>>使わないメソッドがShapeFunctionの実装クラスに存在することもありま
>>すがそれは問題視することもないと思います.
>
>うーん、ShapeFunctionはシリアライズ対象外ですから、データベー
>スに格納されたモノについては、影響を与えなくて、それはそれで
>意味のあることだと思うのですけれども。
>
>使わないメソッドがShapeFunctionにあるということは、あっちの
>アプリを改造すると、こっちのアプリにも影響が出るということに
>なりませんか? javacの場合リコンパイルが要るかどうかはよく知
>りませんけど。

うーんとこの場合のShapeFunction実装クラスは、Shapeサブクラスと同
様に複数のアプリケーションから使われるクラスライブラリの位置付け
ですね.アプリケーションに独自の実装は...の部分(上に引用しました)
にもあるようにShapeFunctionとは独立して作らざるを得ないと思います.

>>前橋さん案は、
>>interface ShapeRunTime {
>>}
>>interface ShapeRunForDraw2D extends ShapeRunTime {
>>	public void draw2D();
>>}
>>interface ShapeRunForDraw3D extends ShapeRunTime {
>>	public void draw3D();
>>}
>>interface ShapeRunForXXXX extends ShapeRunTime {
>>	public void XXXX();
>>}
>>で、使う時にShapeRunForDraw2D/3D/XXXX等にキャストが必要というパタ
>>ーンですね.
>>Shapeが上記のどのinterfaceを実装したクラスを返すかが(利用者に)わ
>>からないのが問題かなあ.って事がいいたかったのです.
↑この部分は誤解があったのですが、
>
>ShapeRunTimeForXXXは利用者毎に分類してあるわけですから、ある
>利用者に必要なShapeRunTimeは一種類の決め打ちでいいわけで...

ある利用者しか使わない実装ですと、ShapeRunTimeのサブクラスである
必要性もとくにない気がするという点と、
# 複数扱うかもしれないShapeと一対一にくっつけて同時に引き渡したり
# できることに意義があるということならわかります.
# アプリケーション側で同時には一つずつしかShapeRunTimeサブクラス
# 相当の機能を使わないなら、先に書いたような単なるメソッドで良い
# と思います.
私の案はアプリケーション側の行う実装ではなく、Shapeに関連するクラ
スライブラリの設計に関する話だったというあたりですね.


後保守に関する視点が欠けてるのでもう少し考えないといけないですが.

──────────────────
木下 信@イデア
やっぱり8月以降は頭の回転が悪い気がする...うまく整理出来ないです.
──────────────────