23

javaで、スーパークラスの機能を減らすサブクラスを設計する良い方法は何ですか?

たとえば、「See」機能を持つクラス「Man」と、その機能を持たないサブクラス「BlindMan」を考えてみましょう。

私が思いつく唯一の解決策は、抽象クラス「Man」と、2 つのサブクラス「SeeingMan」と「BlindMan」を持ち、SeeinMan に関数「See」を追加することです。

ただし、このソリューションの問題は、「DeafMan」クラスを追加したい場合、何を拡張するかということです。シーイングマン?その人が耳が聞こえず、目が見えない場合はどうなりますか?

4

13 に答える 13

14

この場合、継承ではなくコンポジションを使用するか、人間を構成するさまざまなサブクラスを使用する必要があると思います。

私はあなたのロジックを理解していますが、BaseClass はコントラクトであり、そのタイプのすべてのクラスがこの動作に従うことを保証し、親メソッドを削除するサブクラスを持つことは大きな NO NO..

さまざまな例外をスローできますが、私はその道をたどりません。このように考えてみてください。たとえば、私が Human オブジェクトにアクセスする必要があるだけの開発者であるとします。特定の動作を期待すると、突然、インターフェイス メソッドを呼び出して、呼び出したという理由だけで例外を取得しますか?? 派生クラスの実装と、それらを呼び出すことができる場合とできない場合に注意する必要はありません。

以下にいくつかの解決策を示します。

Human を BasicHumanFunctions、VisionSystem などの構成物にします。そうすると、盲人はそれらのほんの一部しか持たないでしょう。

class Human {
  private BasicHumanFunctions _basicFunctions; //contains breathe funcitonality.
  private VisionSystem _vision; //contains see
}

class BlindMan {
   private BasicHumanFunctions _basicFunctions;
}

人間の基本クラスに、すべての人間が呼吸を好むのと同じ動作のみを含めてから、HealthyHuman と BlindHuman などを作成し、それぞれ独自のメソッドを作成します。その後、HealthHuman を使用して、必要に応じてさらにサブクラス化できます。

class Human {
   void breathe() {};
   // other Human basic functions;
} 

class HealthyHuman extends Human {
   void see() {};
   //other healthy human functions
}

class BlindHuman extends Human {
  void useCane() {};
}

2 番目のケースでは、コンポジションを使用して動作を共有することもできます。

class BlindHuman extends Human {
   private VoiceSubsystem _voice = new VoiceSybsystem();
   void speaker() {  _voice.speaker();}
}
于 2013-06-13T06:33:16.720 に答える
1

人間に自分のやり方で物事をさせ、命令ではなくタスクを与えます。

見ることはいくつかの活動の一部であるため、視覚を独立して使用する (または使用しない) ようにします。

たとえば、彼にどこかに旅行するように言います。健康な人は視覚を使いますが、盲人は他の感覚を使うので効率が悪くなります (真っ暗闇でない限り)。

特定のタスクに視覚が必要な場合 (例: 見張り塔の警備員)、彼らの視力がどのくらい良いかを尋ねる必要があります (視力が半端ない盲人はいません)。

時々、彼らに何を見ているか尋ねたいと思うことがあります (そして、彼らが何を聞いているかは気にしません)。それから、盲目 (および他の視覚障害者) に何も見えないことを期待して尋ねてください。

人間を受動的なオブジェクトにし、それらを処理する他のオブジェクトにしたい場合、まだ言及されていないアプローチの 1 つは、ゲーム プログラミングで使用されるエンティティ コンポーネント プログラミングを見てください。基本的には、一般的な方法でコンポジションを使用しています。エンティティはアイデンティティのみを保持し、コンポーネントはエンティティのいくつかの側面に関するデータを保持します (たとえば、視度は、たとえば視度の数またはより有用な統計などです)。システムは、特定のシステムに必要なコンポーネントの組み合わせを持つエンティティのセットを処理します。視力システムは視力コンポーネントを必要とし、現在のエンティティが現在見ているエンティティを含むコンポーネント seenEntities を作成できます。他のシステムは、すべての感覚からの結果を統合し、それを使用して何か有用なことを実行できます。

于 2013-06-13T11:15:12.143 に答える
1

たとえば、「See」機能を持つクラス「Man」と、その機能を持たないサブクラス「BlindMan」を考えてみましょう。

あなたはそれを完全に正しく理解していません。盲人には、何もしない「見る」機能があります (センサーと適切な脳部分の間にリンクがないか、センサーが機能していないためです (ピクセルの空のリストまたはサイズ 0 の画像を返します)。

良い例え: aWriterは関数flush()を持っていますが、その関数を にするものは何StringWriterですか?

/**
 * Flush the stream.
 */
public void flush() { 
}

まあ、何も。流すものはありません。わかりましたが、なぜclose()投げるのIOExceptionですか?

public void close() throws IOException {
}

完璧ではありませんが、このコードは、関係のないライターも含め、すべてのタイプのライターで機能しflushます。

しかし、待ってください、seeing man 関数see()が null または空のリストを返す場合があります。たとえば、暗すぎるとき。null/空の値を確認するだけで、コードはその設計で正常に機能します。

于 2013-06-13T13:47:41.517 に答える
1

クラス Man ではhasEyes、デフォルトで true を追加し、デフォルトBlindManで false にします (または、直後に目を奪われた盲目の男性を Man のインスタンス化します。たとえば、 a BlindManFactory)。次に、Man のSeeコードでは、目がなければ自動的に失敗するようになっています。

于 2013-06-13T06:32:36.030 に答える
1

ブール値を使用できます

例: isSeeing()

関数では、 if else ステートメントでそれを使用できます

于 2013-06-13T06:35:37.197 に答える
1

javaで、スーパークラスの機能を減らすサブクラスを設計する良い方法は何ですか?

それは基本的に「機能を減らすために継承をどのように行うことができますか?」と尋ねます。私が考えることができる Java でのこの例は、Collections#unmodifyableListメソッドです。

指定されたリストの変更不可能なビューを返します。この方法により、モジュールはユーザーに内部リストへの「読み取り専用」アクセスを提供できます。返されたリストに対するクエリ操作は、指定されたリストを「読み取り」、直接または反復子を介して返されたリストを変更しようとすると、UnsupportedOperationExceptionが発生します。

そのため、特定の機能を削除したい場合は、これを使用します。BlindManただし、その使用法が明確であることを確認してください。たとえば、そのJavadoc の状態はsee()例外になります。

ただし、複数の機能を個別に「削減」し、時間とともに変更する場合は、継承よりも変数を使用します。結局のところ、スーパークラスを拡張していないのに、なぜ継承を悪用するのでしょうか? あなたが持っているのは、異なる特性を持つ人間です。

メソッドの動作は文書化する必要があります。私はあなたのユースケースのために次のクラスを考えることができます:

public class Human {
    private boolean seeing;

    public void setSeeing(boolean seeing) { ...}
    public boolean isSeeing() { ... }

    /**
     *  Returns what the human sees at the moment, or null
     *  if he/she can't see (seeing is false).
     */
    public String see() {
        if(seeing){
            return "I can see a tree!";
        }else{
            return null;
        }
    }

    // same goes for hearing
}
于 2013-06-13T09:34:23.783 に答える
0

機能を実装するには、interfaceを使用します。

機能を拡張または再定義するには、基本クラスを拡張して子クラスを使用します。

実行時に動作を動的に追加したい場合は、Decoratorパターンを実装します。

関連する SE の投稿:

実装と拡張: いつ使用するか? 違いは何ですか?

Decorator パターンを使用する場合

于 2016-12-14T12:30:10.233 に答える
0

このようなものはどうですか:

 public class Man {

    Ears ears;

    Eyes eyes;

    }

    public class Eyes {

    public boolean canSee()

    }

    public class Ears {

    public boolean canListen()
    }

次に、ロジックは次のようになります...

if(man.getEyes().canSee()){ //not blind

}
else
{
//blind logic
}

if(man.getEars().canListen())
{
//Not Deaf
}
于 2013-06-13T06:45:48.167 に答える