2

下面的代碼工作得很好,當所有涉及的類都在同一個項目(determineSubClassBaseClass成員):如何扭轉依賴的類工廠搬到了圖書館

protected static BaseClass determineSubClass(String p1, int p2, Boolean p3) { 

    BaseClass baseObj = null; 
    if ((baseObj = SubClassOne.ofType(p1, p2, p3)) != null) 
     return baseObj; 
    else if ((baseObj = SubClassTwo.ofType(p1, p2, p3)) != null) 
     return baseObj; 
    else if ((baseObj = SubClassThree.ofType(p1, p2, p3)) != null) 
     return baseObj; 
    else if ((baseObj = SubClassFour.ofType(p1, p2, p3)) != null) 
     return baseObj; 
    else 
     return new SubClassDefault(p1, p2, p3); 
} 

但現在,我想將BaseClass移動到共享庫項目中,其中SubClassOne,SubClassTwo,SubClassThreeSubClassFour而不是定義在庫中,而是在使用此庫的應用程序中。

我當然可以移動BaseClass回每使用這個庫的每一個應用程序,但我不知道:

  • 有沒有更好的解決辦法?
  • 有沒有可以讓我 保持BaseClass在圖書館 項目,並無需爲它 瞭解來源於它所有超 的解決方案?

EDIT(回答@ahmet ALP巴爾幹以下問題):

每個子類的ofType()做兩兩件事:

  1. 確定,基於 字符串P1和其它的內容參數 p2和p3,子類,以 被實例化是否類型。
  2. 如果答案是肯定的,它 實例自 子類的對象。否則,返回null。

關於你的第二個問題,BaseClass在這一點上持有共同的數據成員和方法,其目的是在確定委託子類實例化的責任,所有子類,只有這一個靜態方法。

BTW,感謝你的問題,我在我原來的職位發現一個可怕的錯字:「SuperClassOne」應爲「SubClassOne」等

+1

什麼呢'ofType'方法做,你可以給我們BaseClass'的'定義。我無法得到你想在這裏實現的目標。 –

+0

@ahmet alp balkan看到我上面的編輯。感謝和+1指出我的問題中不清楚的部分。 – ef2011

回答

1

你的靜態determineSubClass方法是一個工廠方法。它顯然不應該位於BaseClass上,因爲不僅基類不應該知道子類的任何內容,而且在你的情況下它不知道任何事情,因爲你想在另一個項目中找到基類。不,該方法應位於負責創建實例的工廠類中。您應該做的是定義一個接口(或基本類型),用於在BaseType旁創建BaseClass實例,並在您的應用程序的composition root中定義一個實現。當你有多個應用程序時,它們可能每個都有一組不同的子類型,所以每個應用程序都有不同的工廠。當你有這種結構時,你可以將工廠注入需要實例的類中。

它可能是這個樣子:

// Shared library 
public interface IBaseClassFactory 
{ 
    BaseClass CreateNew(String p1, int p2, Boolean p3); 
} 

public abstract class BaseClass 
{ 
} 

// Application code 
public class SubClassOne : BaseClass 
{ 
} 

public class SubClassTwo : BaseClass 
{ 
} 

// Note that this consumer depends on IBaseClassFactory. 
public class SomeConsumer 
{ 
    private IBaseClassFactory baseClassFactory; 

    public SomeConsumer(IBaseClassFactory factory) 
    { 
     this.baseClassFactory = factory; 
    } 

    public void Consume() 
    { 
     BaseClass instance = this.baseClassFactory 
      .CreateNew("foo", 0, false); 

     // use instance 
    } 
} 

// Composition root 
class BaseClassFactory : IBaseClassFactory 
{ 
    public BaseClass CreateNew(String p1, int p2, Boolean p3) 
    { 
     BaseClass baseObj = null; 

     if ((baseObj = SubClassOne.ofType(p1, p2, p3)) != null) 
      return baseObj; 
     // etc 
     else 
      return new SubClassDefault(p1, p2, p3); 
    } 
} 
+0

感謝您的清晰和詳細的答案。除了'SomeConsumer'必須駐留在庫中,還有誰調用'SomeConsumer'的構造函數以及'factory'對象,即在哪裏以及如何創建'factory'對象?對上述任何建議的修改? – ef2011

+0

IOW,它是雞與蛋的情況:'SomeConsumer'依賴於一個**實例**'BaseClassFactory',但在我的情況下'SomeConsumer'必須駐留在庫中。我該如何解決這個問題? – ef2011

+1

@ ef2011:這裏沒有雞和雞蛋:'SomeConsumer'依賴於將在共享庫中定義的'IBaseClassFactory'抽象,而不是在組合ro中定義的'BaseClassFactory'實現中定義OT。仔細看看我的例子,看看'BaseClassFactory'如何繼承/實現'IBaseClassFactory'。 – Steven

1

這並不是說基類知道它的超類一個很好的做法。它違反了大約一半的OO原則;).....

我搬出方法稱爲HierarchyManager或水木清華新類這樣的,有方法,有。你甚至可以建立一些有層次 - >你能有效地使這種方法「擴展」 ......

例如在圖書館,你可以有:

BaseClass的 - > A,B(A,B子類的BaseClass ) 有的LibraryHierachyManager處理這三個類...

,然後在應用程序中使用它:

C,d(子類的BaseClass或A或B)

和一些ApplicationHieararchyManager做:

public static BaseClass determineSubClass(String p1, int p2, Boolean p3) { 
    if (baseObj = C.ofType(.....) { 
    .... 


    } else { 
     return LibraryHierarchyManager.determineSubClass(p1,p2, p3); 
    } 
} 
+0

感謝您的回答。我不確定我是否理解它。如果必須至少有一個知道所有子類的類,那麼它的名字實際上是次要的。我真正需要知道的是這個管理器類應該放在哪裏:如果在庫中,那麼它違反了相同的OO原則,因爲庫不需要「知道」將使用它的所有應用程序。恕我直言,需要有一種方法來「註冊」新的子類。做這件事的正確方法是什麼? – ef2011

+0

我建議將它放在單獨的類中,甚至可能在圖書館中有2個,在主應用程序中有另一個(庫中的所有子類和應用程序中有關所有子類的應用程序)。這正是有所作爲 - 有獨立的類,而不是將其保留在基類中 - 因爲只通過單獨的類就可以將它分離出來並投入應用程序。這就像有一個單獨的工廠類(實際上是你的情況我相信 - 該類應該命名爲SomethingFactory,因爲它的工廠模式。 –

+0

Potiuk謝謝+ 1澄清這一點。 – ef2011