2016-06-14 7 views
-1

要するに、クラスインスタンスを特定のインタフェースを実装していないスーパークラスでグループ化できるようにしたいと思います。しかし、インスタンスのセットから、そのインターフェイスを実装するインスタンスのインターフェイスからメソッドを呼びたいと思います。インタフェースへのオブジェクトダウンキャスト

説明できるコード例をいくつか示します。

class Building{ 
    String c = "white"; 
    Building(){ 
    } 

    void printColor(){ 
    println("The building is " + c); 
    } 

    void paint(String c){ 
    this.c = c; 
    } 

    void printBuildQuality(){ 
    println("The build quality is average"); 
    } 
} 


class SturdyFactoryBuilding extends Building implements Factory{ 

SturdyFactoryBuilding(){ 
    super(); 
} 

void printBuildQuality(){ 
    println("The build quality is sturdy"); 
} 

void printFactoryOutput(){ 
    println("This factory makes stuff"); 
} 
} 

class ShakyFactoryBuilding extends Building implements Factory{ 

    ShakyFactoryBuilding(){ 
    super(); 
    } 

    void printBuildQuality(){ 
    println("The build quality is shaky"); 
    } 

    void printFactoryOutput(){ 
    println("This factory makes slightly different stuff"); 
    } 
} 


public interface Factory{ 

    public void printFactoryOutput(); 

} 

Building building = new SturdyFactoryBuilding();  
building.printBuildQuality(); 
building.printColor(); 
building.paint("bright red"); 
building.printColor(); 
building.printFactoryOutput(); 

スーパークラスに 'isFactory'フラグが設定されている可能性があります。

ありがとうございました。

私はあなたがトレードオフをしなければならないと思う
+3

単純な 'if(Factory instanceof Factory)'チェックで実現できます。しかし、あなたがしようとしていることは良いデザインとは考えられません。 – Kayaman

+0

私は@ Kayamanを見ていますので、このようにしてください: 'if(building instanceof Factory){ SturdyFactoryBuilding sfb =(SturdyFactoryBuilding)building; sfb.printFactoryOutput(); } '特定のサブクラスにダウンキャストする必要があるので、どうすればよいデザインにならないのか分かります。これについてもっと良い方法がありますか? – Bluefarmer

+0

'printFactoryOutput'を' Building'に追加して、NOOPのデフォルト実装を与えることができます。ファクトリはデフォルトをオーバーライドします。アダプターの種類 - アプローチ。 – Fildor

答えて

0

:アダプタとして動作するようにあなたには、いくつかのアンチパターンを受け入れるか、あなたを開くBuilding「インターフェース」のいずれか:

class Building implements Factory{ 

    // the other building stuff 

    @Override 
    public void printFactoryOutput(){ /* NO OP */ } 
} 

次にあなたが呼び出すことができますprintFactoryOutput on all Buildingこの時点までは何の効果もありません。

Factoryの実装がBuildingに拡張されているため、それらは自動的にNOOP実装を継承します。しかし、あなたはそれを上書きするので:

class ShakyFactoryBuilding extends Building implements Factory{ 

    ShakyFactoryBuilding(){ 
    super(); 
    } 

    @Override 
    public void printBuildQuality(){ 
    println("The build quality is shaky"); 
    } 

    @Override 
    public void printFactoryOutput(){ 
    println("This factory makes slightly different stuff"); 
    } 
} 

を...あなたは、所望の結果を持っています。

もちろん、すべての建物にはprintFactoryOutputが表示されます。しかし、それは私が話していたトレードオフです。これが受け入れられない場合は、デザインを完全に再考する必要があります。

ではなく、のFactoryがそのメソッドを呼び出さないようにするには、ビルドでUnsupportedOperationExceptionをスローすることができますが、これはコード内のtry/catchブロックを強制します。ブール値を返すこともできます。デフォルト= falseで、実際には工場の場合はtrueを返します。可能性は十分です。

composition over inheritanceを使用するようにデザインを変更することもできます。

+0

ありがとうございます。私はインタフェースメソッドを実装するためにスーパークラスを修正します。それは、私にとって最低限のもの(少なくとも再設計なしで)を守っています。 Factoryインタフェースがスーパークラスに実装されている場合、Factoryを実装するサブクラスで独自のメソッドオーバーライドを持つ必要はありません。強制する方法はありますか、または「工場を実装する」ことができるのですか?「工場」のサブクラスから除外することができますか?私の主な質問に答えるので、私はあなたの答えを受け入れるでしょう。 – Bluefarmer

+0

BuildingはFactoryを実装しているので、XXXFactoryクラスから削除することができます。 – Fildor

0

これは悪い考えであるというメッセージが表示されていると思います。それは一般的に受け入れられるオブジェクト指向の設計原則に違反します。しかし、それについてはいくつかの方法があり、他の方法よりもあまり嫌なことはありません。あなたはその後、鋳造後Factory固有のメソッドを呼び出し、それはFactoryだかどうかをチェックしている

if (building instanceof Factory) 
    ((Factory)building).printFactoryOutput(); 

ちょうどそれに

を投じる最も簡単な方法は、このようなものです。それは、悪い設計を実装する簡単な(したがって容易に理解される)方法です。

Factory

Buildingを認識させるこれがBuildingFactoryの間には、必要な関係は現在ありませんが、そのような関係に沿ってあなたを助けるかもしれないという点で問題があります。

class Building { 
    // ... 
    Factory adaptToFactory() { 
     return null; 
    } 
} 

class SturdyFactoryBuilding ... { 
    // ... 
    @Override 
    Factory adaptToFactory() { 
     return this; 
    } 
} 

ShakyFactoryBuildingについても同様である。

次に、あなたは

Factory f = building.adaptToFactory(); 
if (f != null) 
    f.printFactoryOutput(); 

あなたはこの種のものをたくさんやっている場合は、一般的なアダプタ

よりは、あなたが必要なところはどこでもあなたが適用されたパターンにそれを作ることができます書くことができます。 (Eclipseは、例えば、あらゆる場所にアダプタを使用しています。)

interface Adaptable { 
    <T> T adapt(Class<T> clazz); 
} 

class Building implements Adaptable { 
    // ... 
    @Override 
    <T> T adapt(Class<T> clazz) { 
     if (clazz.isInstance(this)) { 
      return clazz.cast(this); 
     } 
     return null; 
    } 
} 

次にあなたが

Factory f = building.adapt(Factory.class); 
if (f != null) 
    f.printFactoryOutput(); 

あり、これに行くために多くの場所が残っているが、これは、このために十分であると記述します。質問、私は思う。

+0

残念ながら、システムを再設計するオプションはありません。しかし、インタフェースには、Fildorが記述したやり方や、「adaptToFactory」の両方の方法が妥当と思われる方法しかありません。 – Bluefarmer

関連する問題