2016-05-20 63 views
1

我的計劃是有一個ControlPanelFactory,將建立一個定製ControlPane爲每個不同的Model類:工廠模式和多態性

abstact class Model { 
} 

class ModelA extends Model { 
} 

class ModelB extends Model { 
} 

現在我的計劃是有一個創建基於不同ControlPane實例的工廠類在Model類與方法的重載通過:

class ControlPaneFactory { 
    private ControlPaneFactory() { 
    } 

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

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

然而,這是非常有問題的,因爲調用廠區方法時,我只有一個VARI能夠類型Model,所以我需要首先使用instanceof,這是一個巨大的代碼。同樣apllies具有濃縮工廠方法:

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"); 
} 

我想過usign,將指定的Model類型的模型類中的枚舉,但是這也似乎是這將違反DRY一個壞的選擇。

此外,我更希望具有Model類別的獨立(即在一個spererate類)的ControlPane的實例化。有沒有一種「很好」的方式來解決這個問題?

回答

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); 

至少這將提取邏輯如何面板依賴模型。我再次認爲這不是最乾淨的解決方案。

2

如果您希望您的所有工廠方法都在同一個對象中,那麼您將以這種或那種方式需要一個switch/instanceof組或者ModelsControlPanels的映射。

或者,您可以將工廠方法移至Model類。實質上,這是抽象工廠模式,但是您正在使用您的Model對象實現它。有幾種方式來看待這一點。有人可能會認爲它會增加您的ModelControlPanel對之間的耦合,但我建議您嘗試實現這一點。也可以認爲它使得你的工廠代碼不能重複使用,因爲你需要一個Model對象來運行它,但是你爲工廠對象給出的示例接口無論如何都需要構建Model。隨着遠離貧血模型,我認爲這是實現它的合理方式,並降低了工廠對象的複雜性(如果您仍然需要的話)。

我會去像這樣的東西:

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(); 
    } 
} 

這將仍允許您如果需要爲您的ControlPanel小號完全不同構造的靈活性,你不會需要註冊一個地圖程序啓動時的對象。

您可以將buildControlPanel()方法移出Model s,並創建一個適當的抽象工廠模式,而是從您的Model對象返回一個具體的工廠。但是我覺得這樣做只會增加你有的班級數量,而沒有真正提供任何改進。如果你有很多Model類使用相同的構建代碼(如ModelA,ModelB,ModelC都對應於ControlPanelX),那麼它可能是一個好方法,但它聽起來並不像你這樣做。

儘管如此,一個開關或if語句選擇具體類來實例化並不是世界上最糟糕的事情。其他圖書館也使用類似的東西,如Eclipse's EMF Switch Class

+1

將'ControlPane'實例化到相應的'Model'類將是顯而易見的解決方案,但正如您所說,這確實增加了視圖和模型之間的耦合,這正是我想要避免的。抽象工廠肯定會矯枉過正。我只是想知道是否有一個明顯而優雅的方式可以解決這個問題,但是如果你想從'Model'中解耦ControlPanel,總會有一些東西不太典雅。 – Marv