2010-03-08 16 views
2

在我當前的項目中,我們有幾個處理應用程序域核心概念的數據類。現在在我們項目的一些地方,我們必須根據手中的具體物體有不同的行爲。例如。 JList具有渲染對象列表的任務,但我們希望渲染略有不同,具體取決於對象的類別。例如。 A類的對象應該與B類中的一個不同,而C類也是完全不同的動物。出廠配置。對象的類 - 如何很好地做到這一點?

我們將行爲封裝在策略類中,然後有一個工廠返回適合要呈現的對象的類。從客戶的角度來看,我想沒關係。

從工廠這個得到相當醜陋的角度

現在,因爲我們只能拿出這麼遠是這樣的東西

if (obj instanceof classA) return strategyA; 
else if (obj instanceof classB) return strategyB; 
... 

現在,已經實例化對象池,地圖也將工作。但是,如果工廠必須實際創建一個新對象,那麼我們必須將另一層工廠/策略對象放入該映射中,然後返回適合的顯示策略。

是否有任何設計模式可以很好地處理這類問題?

回答

1

執行此操作的一種方法是將實現委託給對象本身。舉例來說,如果類ABC都呈現不同的,你可能有他們各自實現的接口,如:

interface IRenderable { 
    public void render(); 
} 

然後,每個人會提供它自己的實現的render()。要呈現ListIRenderable,您只需遍歷其成員並調用各自的render()方法即可。

使用這種方法,您永遠不必顯式檢查對象的類型。如果你的任何課程都是分類的,這個特別有用。假設您有classD級別,它延伸classA,並且與A的渲染方式不同。現在的代碼如下:

if (obj instanceof classA) return strategyA; 
... 
else if (obj instanceof classD) return strategyD; 

將會失敗 - 您總是需要按照從大到小的順序進行檢查。最好不要去想這些事情。

編輯:響應您的評論 - 如果你的目標是保持前端代碼出來的模型對象的,但你仍然要避免明確的檢查,你可以使用visitor pattern

事情是這樣的:

class Renderer { 
    public void visit(classA obj); 
    public void visit(classB obj); 
    // etc 
} 

class classA { 
    public void accept(Renderer r) { 
     r.visit(this); 
    } 
} 

現在,所有的渲染代碼進入Renderer,模型對象選擇調用哪個方法。

+1

非常感謝您的回答。您的想法很有趣,但有一個缺點,即數據對象應該只是模型,會收集大量的前端代碼。此代碼在可移植性,代碼大小,測試等方面都存在常見問題。 – xmjx 2010-03-08 19:58:35

0

你可以有你的模型類實現等的接口:

public interface RenderingStrategyProvider { 
    public RenderingStrategy getRenderingStrategy(); 
} 

,並返回相應的策略的一個實例。像:

public ClassA implements RenderingStrategyProvider { 
    public RenderingStrategy getRenderingStrategy() { 
     return new ClassARenderingStrategy(this); 
     // or without this, depending on your other code 
    } 
} 

在這種情況下,你甚至不需要工廠。或者如果你想要的話,它將只包含一個方法調用。這樣你的模型類中就沒有表現邏輯了。

或者,您可以使用約定+反射,但這是一個奇怪的。對於一個模型類的策略是ModelClassStrategy,你可以有:

public RenderingStrategy createRenderingStrategy(Object modelObject) { 
    return (RenderingStrategy) Class.forName(
      modelObject.getClass().getName() + "Strategy").newInstance(); 
} 
1

相反,如果/ else塊你可以有一個工廠接口,這樣

interface RendererFactory { 
    supports(Object obj); 
    createRenderer(Object obj); 
} 

然後你就可以有一個如果其中一個支持給定類型,則會詢問其他實現的列表。其他實現可以在supports方法中執行instanceof檢查。 渲染器的使用者只需要撥打createRenderer即可。

優勢:您RendererFactories可能的配置

缺點:你必須採取有關RendererFactories的井井有條(但你必須做到這一點與if/else語句太)

+0

+1。與Adaptable模式類似,以及Eclipse如何使用它來呈現UI中的元素。 – mhaller 2010-03-08 21:34:27

1

我喜歡出廠服務策略對象很多。但我想知道你是否可以像IoC那樣對待它併爲特定類型註冊策略?你沒有一堆if-else,但你必須「註冊」它們。但是,對於測試而言,它可能也很好 - 而不是實施一個'模擬工廠',你會註冊'模擬策略'?

相關問題