- PR -

Widening

投稿者投稿内容
トリックスター
大ベテラン
会議室デビュー日: 2003/04/16
投稿数: 104
投稿日時: 2003-04-21 23:31
ものすごく簡単な質問かもしれないのですが、思い付かなかったもので
教えていただければ幸いです。

あるclassには、多く(仮に10個)のフィールドがあります。
class A {
private Object field1;

private Object field10;
}
そのclassを継承し、フィールドを新たに1個加えたclassを作ります。
class B extends A {
private Object fieldX;
}
getter()、setter()メソッドは省略

class Aのフィールド値をclass Bにコピーし(あるいは参照させ)、
新たに加えた値をセットして、新しいデータとしたいのですが、どの
ようにすればスマートなのでしょうか。

言いたいことがうまく伝えられなくて、申し訳ないのですが、イメー
ジ的には、こんな感じです。

A aObject = new A();
aObject.setField1(f1);

aObject.setField10(f10);

// ここからがやりたいこと
B bObject = (B)aObject; // <-当たり前ですが、ClassCastException
bObject.setFieldX(fX);

できれば、全フィールドコピーしてから、新たに加えた値をセットす
るのは、class Aのフィールドを追加した際、フィールドのコピー処
理も追加しなければいけないので、避けたいです。

いろいろ調べて、...(あさっての方向を見てるかもしれない)

リフレクションを使う手もありますが、スマートじゃない気がします
(遅そうですし)。

Serializeが関係ありそうな気がしますが、ファイルに一旦書き出し
たりしたくないです。

過去のclone()の書き込みなども見てみたのですが、混乱してしまい
ました。

より敷くお願いします。
YOU@IT
ぬし
会議室デビュー日: 2002/03/29
投稿数: 284
お住まい・勤務地: 大阪
投稿日時: 2003-04-22 08:50
ちょっと外しているかもしれませんが、継承ではなく
クラスBでクラスAをラップするようにしては?

class B {
private A a;
private String field;

public B(A a){
this.a = a;
}

public void setField(String s){ ... }
public String getField(){ ... }

// aへの転送メソッドを列挙
}

使うときは

A a = new A():
a.setXxx( ... );
....
B b = new B(a);
b.setField( ... );

のような感じで。


[ メッセージ編集済み 編集者: YOU@IT 編集日時 2003-04-22 08:51 ]
HALcat
会議室デビュー日: 2003/04/22
投稿数: 3
投稿日時: 2003-04-22 17:31
> // ここからがやりたいこと
> B bObject = (B)aObject; // <-当たり前ですが、ClassCastException
> bObject.setFieldX(fX);

ここでClassCastExceptionだと分かってらっしゃるみたいなので、
B のオブジェクトを作って持ち回り、必要なところで

A aObject = (A)bObject;

というのはいかがでしょう?
class A の変更は class B の変更を必要としません。

はずしてないといいですが。
ずれてそうなら、もう少し状況をくださいな。
HIRO
常連さん
会議室デビュー日: 2003/04/15
投稿数: 20
投稿日時: 2003-05-01 14:01
初めまして、デビュー投稿になります。

Aにcopy()メソッドを実装しておいて、Bのコンストラクタで呼び出すのはどうですか?
※以下、かなり端折ってますが・・・

class A {
private Object field1;
private Object field2;

public copy(A org) {
this.field1 = org.field1;
this.field2 = org.field2;
}
}

class B extends A {
private Object fieldX;
public B(A a) {
copy(a);
}
}

使い方はYOU@ITさんと同じです。

A objA = new A();
objA.setField1(...);
objA.setField2(...);

B objB = new B(objA);
objB.setFieldX(...);
zaxx_MD
大ベテラン
会議室デビュー日: 2003/04/21
投稿数: 204
お住まい・勤務地: 千葉県柏市
投稿日時: 2003-05-01 18:09
それは厳密にはcopyとは違いますね。
field1とfield2はプリミティブではなくオブジェクトですから、
参照渡しになります。
しかし用途としては間違ってないと思いますので、
copyをcastなどのメソッド名称にすることをお勧めします。
helmet
会議室デビュー日: 2003/05/01
投稿数: 2
投稿日時: 2003-05-01 18:23
ちょっと邪道かもしれないですが、
Jakarta CommonsのBeanUtilsを使うってのはどうでしょう?
org.apache.commons.beanutils.BeanUtils.copyProperties(java.lang.Object dest, java.lang.Object orig)で
異なるインスタンスで同じ名前のプロパティをコピーできます。
(getter,setterがあることが条件)

フィールド数が多いときとか、BのサブクラスのCでも同じことがやりたくなったり
した場合に有効だと思うのですが。

zaxx_MD
大ベテラン
会議室デビュー日: 2003/04/21
投稿数: 204
お住まい・勤務地: 千葉県柏市
投稿日時: 2003-05-01 18:33
そうですね。

フィールド数が多いときは、開発効率を考えるとBeanUtilsを使うのがいいと思います。

ただし、reflectを使っているのでパフォーマンスを気にする時には
使わないほうがいいでしょう。
トリックスター
大ベテラン
会議室デビュー日: 2003/04/16
投稿数: 104
投稿日時: 2003-05-04 14:46
レスポンスが遅くなりまして、誠に申し訳ございません。

皆さんのご意見、非常に参考になりました。ありがとうございました。
結論としては、クラスAにcopy(cast)メソッドをつくりました。

以下、時間が経ってしまい非常に心苦しいのですが、念のためお返事
させていただきます。
−−−−

YOU@IT様
>ちょっと外しているかもしれませんが、継承ではなく
>クラスBでクラスAをラップするようにしては?
aへの転送メソッドを列挙しなければいけない点が、要件にあいません。
クラスAに変更(フィールドの追加や削除)があった際にコードを変更
したくありません。

HALcat様
>B のオブジェクトを作って持ち回り、必要なところで
>A aObject = (A)bObject;
この案は、最終的な逃げ道として使おうと思っておりました。
クラスAを使用する機能から、クラスBを使用する際の情報まで
見えてしまう点が、納得いっておりません。

HIR様
結論としては、この方法を採用しました(リフレクションを使って)。
しかし、本当はクラスAにcopy(cast)メソッドを追加したくない。
この操作はクラスAの機能ではなく、ユーティリティ的な扱いとしたい。
すごいわがままですね。> 自分

helmet様
zaxx_MD様
>Jakarta CommonsのBeanUtilsを使うってのはどうでしょう?
調査の過程で、気がついたらこれと同じ物を自分で作ってました。
なぜ、getter,setterがあることが条件でなければならないのかが
疑問でしたが、フィールドがprivateだから、ユーティリティクラス
からアクセスする際、getter,setterがひつようなのですね。

独り言
streamをつかってクラスAからクラスBに出力できないかな?
−−−−

皆さん、ありがとうございました。

スキルアップ/キャリアアップ(JOB@IT)