2016-05-20 10 views
1

私の計画は、異なるModelクラスごとにカスタマイズControlPaneを構築しますControlPanelFactoryを持つことです:私の計画は、ベースの異なるControlPaneインスタンスを作成するファクトリクラスを持っていた今 Factoryパターンと多型は、

abstact class Model { 
} 

class ModelA extends Model { 
} 

class ModelB extends Model { 
} 

メソッドのオーバーロードで可決された Modelクラス上:factorysメソッドを呼び出すときに、私は唯一のバリを持っているので、

class ControlPaneFactory { 
    private ControlPaneFactory() { 
    } 

    public static ControlPanel build(ModelA model) { 
     return new ControlPaneA(model); 
    } 

    public static ControlPanel build(ModelB model) { 
     return new ControlPaneB(model); 
    } 
} 

しかし、これは、非常に問題がありますタイプModelであることができるので、最初にinstanceofを使用する必要があります。これは、巨大なコードマレットです。凝縮ファクトリメソッド持つと同じapllies:私はModelの種類を指定しますモデルクラス内の列挙型をusignについて考え

public static ControlPane build(Model model) { 
    if (model instanceof ModelA) 
     return new ControlPaneA(model); 
    else if (model instanceof ModelB) 
     return new ControlPaneB(model); 
    else throw new IllegalArgumentException("Unsupported model"); 
} 

が、しかし、これはまた、DRYに違反する不正なオプションのように思えます。

さらに、私は、ControlPaneクラスの独立した(すなわち、spererateクラスの)クラスのインスタンス化をすることを好むでしょう。この問題を解決する "良い"方法はありますか?

答えて

1

コードをより一般的なものにしようとすると、ControlPanelは特定のモデルに依存してはいけません。しかし、本当に必要な場合は、これを試すことができます:

public class ControlPanelFactory { 
    private static Map<Class<? extends Model>, Class<? extends ControlPanel>> modelPanelMap = new HashMap<>(); 

    public static void addModelPaneRelation(Class<? extends Model> model, Class<? extends ControlPanel> pane) { 
     modelPanelMap.put(model, pane); 
    } 

    public static ControlPanel build(Model model) { 
     try { 
      return modelPanelMap.get(model.getClass()) 
        .getConstructor(model.getClass()) 
        .newInstance(model); 
     } catch (Exception exception) { 
      // Handle exceptions 
     } 

     return null; 
    } 
} 

あなたはあなたのアプリケーションを起動するときに何らかの設定が必要です。これは次のように実行します:

ControlPanelFactory.addModelPaneRelation(ModelA.class, ControlPanel.class); 

少なくとも、これはPanelがモデルに依存する方法を抽出します。繰り返しますが、これは一番クリーンな解決策ではないと思います。

2

同じオブジェクトにすべてのファクトリメソッドが必要な場合は、switch/instanceof if group、またはModelsControlPanelsのマップが必要です。

また、ファクトリメソッドをModelクラスに移動することもできます。本質的には、これは抽象的なファクトリパターンですが、Modelオブジェクトを使用して実装しています。これを見るにはいくつかの方法があります。あなたのModelControlPanelの組み合わせが増えていると主張できますが、それを達成しようとしていることをお勧めします。また、Modelオブジェクトを実行する必要があるため、工場コードの再利用性が低下すると主張できますが、ファクトリオブジェクトに対して指定したインタフェース例には、必ずModelが組み込まれている必要があります。貧血モデルから離れるにつれて、それを実装する合理的な方法だと思うし、工場オブジェクトの複雑さを減らすことができます(まだ必要な場合)。

私はこのようなものでいいと思う:これはまだ必要であれば、あなたのControlPanelのための乱暴異なるコンストラクタの柔軟性を持つことができるようになります、そしてあなたがマップを登録する必要はありません

abstact class Model { 
    public abstract ControlPanel buildControlPanel(); 
} 

class ModelA extends Model { 
    public ControlPanel buildControlPanel() { 
     return new ControlPanelA(this); 
    } 
} 

class ModelB extends Model { 
    public ControlPanel buildControlPanel() { 
     return new ControlPanelB(this); 
    } 
} 

// Don't really need this anymore... 
class ControlPaneFactory { 
    public static ControlPanel build(Model model) { 
     return model.buildControlPanel(); 
    } 
} 

あなたのプログラムが始まるときのオブジェクトの数。

ModelからbuildControlPanel()メソッドを移動し、適切な抽象ファクトリパターンを作成して、Modelオブジェクトからコンクリートファクトリを返すことができます。しかし、実際に何の改善もなしに、あなたが持っているクラスの数を増やすような気がします。同じビルドコード(ModelAModelBModelCなどすべてがControlPanelXに対応)を使用する多くのModelクラスを使用している場合、それは良い方法かもしれませんが、そうしているようには聞こえません。

ただし、インスタンス化する具体的なクラスを選択するswitchまたはif文は、世界で最悪のことではありません。他のライブラリでも同様のものが使用されています(Eclipse's EMF Switch Classなど)。

+1

'ControlPane'のインスタンス化をそれぞれの' Model'クラスに移すことは明白な解決策ですが、あなたが言ったように、これは避けようとしているビューとモデルの間の結合を増やします。抽象的な工場は確かに過度のものになるでしょう。明白でエレガントな方法があるのか​​どうか疑問に思っていましたが、 'Model'から' ControlPanel'を分離したい場合は、常にエレガントではないものがあります。 – Marv