- PR -

クラス設計(継承に関して)

投稿者投稿内容
びしばし
大ベテラン
会議室デビュー日: 2002/03/13
投稿数: 181
投稿日時: 2004-03-08 13:34
Hand クラスを変更できるのなら、null を返すなり Exception を投げるなりする getThum() を追加してしまいたいですね。(ついでに boolean hasThum() とか)

おそらくそういうことができない状況なのでしょうけれど、参考になれば...。
架空兎
ベテラン
会議室デビュー日: 2003/08/18
投稿数: 78
お住まい・勤務地: さいたま氏
投稿日時: 2004-03-08 17:41
Animal クラスのサブクラスによって、getHand メソッドが返すオブジェクトの型が
異なるのであれば、私は Hand オブジェクトの保持と getHand メソッドの実装を
Animal クラスのサブクラスに任せます。

で、Animal クラスは何をするかというと getHand メソッドの定義だけをします。
つまり、Animal クラスを抽象クラスにします。

そして、Human#getHand メソッドが返すオブジェクトの型が
HumanHand クラスしかありえない場合は、Human クラスに HumanHand オブジェクトを返す
getHumanHand メソッドを作ります。

コード:

public abstract class Animal {
    public abstract Hand getHand();
}

public class Human extends Animal {
    private HumanHand myHumanHand;

    public Human() {
        this.myHumanHand = new HumanHand();
    }

    public HumanHand getHumanHand() {
        return this.myHumanHand;
    }

    public Hand getHand() {
        return this.getHumanHand();
    }
}


ただ、HumanHand クラスのインスタンスが Hand オブジェクトとして振る舞うことが
ないのであれば Animal クラスと Human クラス、Hand クラスと HumanHand クラスを
それぞれ独立させた方がいいかも知れません。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-03-09 00:28
unibon です。こんにちわ。

引用:

Clusterさんの書き込み (2004-03-08 01:54) より:
実際には、HumanクラスのgetHand()メソッドのリターンはHandクラスになるので、
コード:
Human myHuman = new Human();
Thum myThum = null;

myThum = ( (HumanHand) myHuman.getHand() ).getThum();


と書かなくちゃいけなくて、冗長でいやだなぁっていうのが動機です。


私はあまり良く分からないのですが、とりあえず思っていることを書いてみますと、Human に対して getHand して返ってくる Hand 型の返り値の実行時のクラスが HumanHand であることはどこで規定されているのか(規定されていないのではないか?)、という疑問があります。
たしかに Human クラスは HumanHand クラスをフィールド(集約)として持っています。しかし、だからと言ってそのフィールドと getHand メソッドが結びつくとは、クラスの継承関係では規定されていません。
そのような結び付けを規定するとすれば、Human クラスに getHumanHand メソッドを追加することがシンプルなような気がします。

引用:

Clusterさんの書き込み (2004-03-08 01:54) より:
# 人間の手に親指があるのは分かってるんだから、いちいちキャストしなくても・・・
# 横着すぎるかな?(笑)


たしかに「HumanHand」には親指はあるのは分かりますが、人間の「Hand」が「HumanHand」であることは自明ではないような気がします。

上記をまとめますと、結論としては、
引用:

ぽんさんの書き込み (2004-03-05 22:33) より:
getWing()関数をBirdクラスに追加すれば良いのでは?


と同じになりますが。
Cluster
ぬし
会議室デビュー日: 2003/03/06
投稿数: 289
お住まい・勤務地: 大阪
投稿日時: 2004-03-09 03:03
みなさん、ご意見ありがとうございます。

引用:

びしばし さんの書き込みより:

Hand クラスを変更できるのなら、null を返すなり Exception を投げるなりする getThum() を追加してしまいたいですね。(ついでに boolean hasThum() とか)

おそらくそういうことができない状況なのでしょうけれど、参考になれば...。



現時点ではHandクラスは変更可能です。
が、今後MonkeyHandクラスやDogHandクラスができ、それら用の固有のメソッドを
定義するたびに、Handクラスを変更するのは避けたいです。

#DogHandって・・・(笑)

引用:

unibon さんの書き込み より:

Human に対して getHand して返ってくる Hand 型の返り値の実行時のクラスが HumanHand であることはどこで規定されているのか(規定されていないのではないか?)、という疑問があります。


HumanクラスのgetHand()の返り値がHumanHandクラスのインスタンスであることは、
Humanクラスの定義で規定できるから、HumanHandクラスを返り値に指定できればいいのに、
と考えてました。(指摘のとおり、継承関係だけからは規定できませんが)

結局、unibonさん、架空兎さん、ぽんさんが言われているように、getHumanHand()を
別途定義するというのがこの場合の最善策なのかな?

P.S. ところで、「親指」のスペルが間違ってました(爆)。 正しくはThumbです。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-03-09 09:51
unibon です。こんにちわ。
今まで知らなかったのですが、バージョン 1.5 だとコンパイルできるみたいです。
たとえば、こんな感じ。

コード:
class XXXX {
    public Object ffff() {
        return "XXXX";
    }
}

class YYYY extends XXXX {
    public String ffff() {
        return "YYYY";
    }
}

public class OverrideTester {
    public static void main(String[] args) {
        YYYY yyyy = new YYYY();
        String s = yyyy.ffff();
        System.out.println("s = " + s);
    }
}


コンパイルしてしまえば 1.5 未満でも動くみたいです。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2004-03-09 12:32
自分
引用:

C++では、返値が同一の継承階層であれば、別のクラス返すようにオーバーライドすることができます。
即ち、今回例示したままのスタイルで、設計することができます。

この仕様、C++以外にも導入されるという話を以前何かで見たような気がしたけど、Javaだったっけ?
それともC#?



Unibonさん
引用:

コード:
class XXXX {
    public Object ffff() {
        return "XXXX";
    }
}

class YYYY extends XXXX {
    public String ffff() {
        return "YYYY";
    }
}

public class OverrideTester {
    public static void main(String[] args) {
        YYYY yyyy = new YYYY();
        String s = yyyy.ffff();
        System.out.println("s = " + s);
    }
}





やっぱ、Javaだったのね。
でも、C++触ってた頃から、この仕様のお世話になったことないのよね〜
個人的にはあまり利用しなさそうな気が。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2004-03-09 16:24
まず、既に指摘があるようにAnimalクラスにgetHandメソッドがあることが不自然です。
ここに出てきた記述でははっきりしないのですが、HumanクラスのインスタンスをAnimal
型として扱うことがあるのでしょうか? でなければAnimalクラスにgetHandを持たせる
意味はないでしょうし、扱うことがあるとすると、例えばDogクラスのインスタンスを
Animal型として扱うときにどうするか、というのが問題になると思います。

少し気になるのは、Animalクラスとそのサブクラスを構造を持ったデータ型として扱い、
その振る舞いを外部で定義しようとしているのではないか、ということです。振る舞いは
情報を持っているクラスに任せるのが基本ですが、そのようになっていないのではないですか?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-03-09 19:19
unibon です。こんにちわ。

ちなみに、戻り値の型をオーバーライド時に変えることについては、
http://www.mamezou.com/tec/Tips/javaGenericsVsCppTemplate/article2.html#Section1-18
に、分かりやすい解説があるのを見つけました。

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