11

我已經越來越熟悉工廠模式(與戰略模式一起)以及模式可以帶來的好處。但是,我一直在努力處理以下情況:用工廠模式保存數據?

以前,我會做類似以下的事情,那裏有一個可以構建和保存Car的管理器類。在這裏沒有依賴注入,並且是一個糟糕的實現,特別是在嘗試單元測試時。

public class CarManager 
{ 
    public static Car GetCarFromDatabase(int carId) { return new Car(); } 

    public static void SaveCar(Car car) { } 
} 

我現在看我怎麼可能有不同的Factories是製造汽車對我來說,無論是從數據庫或其它地方!這很棒!所以,這裏是我的問題:

問題1:據我瞭解,Factories應該只有構建的對象,是對的嗎?如果是這樣,我的第二個問題呢?第二季度:如果我遵循工廠模式建造我的物品,我應該如何去保存我的物品?有沒有不同的模式,或者我不完全瞭解工廠模式?

+0

工廠真的不應該構建對象 - 他們的目的是選擇從一組相關類型的對象,所有從相同的基本繼承的正確的具體類型。你確定你是指工廠而不是建築商? – 2010-10-27 17:06:45

回答

14

Factory模式應該有助於創建對象。這就是爲什麼它被歸類爲「創造」模式。要回答你的第一個問題,不應該用它來堅持對象。

Repository pattern是一種持久性模式,應該用於將對象保存到持久性機制或從持久性機制中檢索數據。事實上,馬丁福勒認爲,企業模式應該與典型的設計模式不同。

在考慮你的問題時,你想看看S principle in SOLID,其中指出一個班級應該有一個責任,這意味着它應該有一個單一的理由來改變。在這種情況下,當談論一個創建對象並保存(保持)對象的對象時,你有一個有兩個改變理由的類。現在,它可能看起來像是一個單獨的責任,因爲Repository可以檢索對象並將其保存到應用程序中,並且檢索可以看起來像工廠(通常是存儲庫中的工廠對象),但是在您描述的內容,你的對象有太多的責任。

+0

謝謝@Dave White。在查看您的帖子後,我觀看了Repository模式下的Pluralsight視頻,這就是我一直在尋找的。感謝您的回覆! – JSprang 2010-10-27 18:57:44

3

工廠不應保存數據。數據訪問對象(DAO)或表映射器將是一個更好的主意。

1

總的來說,我認爲你從錯誤的角度來看待這個問題。

您需要確定您嘗試解決的問題,然後查找適合該問題的解決方案。這聽起來更像是你發現了某種模式,然後試圖將它應用於你遇到的每一個問題。

您提到的代碼中提到的唯一問題是單元測試並不容易。讓類更可測試的一個解決方案是顛倒它們的依賴關係。所以我會開始研究這個類所依賴的其他類,並開始製作這些可注入的依賴關係。作爲一個起點,我建議你閱讀依賴倒置/控制倒置。

1

Q1 - 是的,工廠模式應理想地用於創建對象。因此,您可以使用工廠模式創建您的Car對象。 Q2 - 爲了保存您的汽車物件,您不應使用工廠模式。解耦Car對象創建並保存汽車對象。而且,如果沒有準確理解需求,很難提出一種設計模式來保存汽車目標。在我看來,如果你只需要保存你的汽車物件,那麼你所需要的只是你的汽車經理類中的一種保存方法。不要過度使用設計模式。

2

一切都取決於你的需求和你想要做什麼事情,模式是沒有標準的做法,他們鼓勵代碼重用,模式不抓住石頭。那麼,爲什麼你不應該使用工廠模式來使對象持久化?這是我如何使用這種模式來解決從/向不同數據庫讀/寫數據的問題,也許這不是使用該模式的更好形式,但它目前正在工作,可擴展,分佈在不同的層之間,幾乎每個人都可以把它理解:

namespace Domain.App 
{ 
    public class PresentationClass 
    { 
     private Collection<ISomeOutput> GetData(ISomeInput1 input) 
     { 
      ServicesLogicContext logic = new ServicesLogicContext((MyType) Identifier); 
      return logic.GetSomeData(input) as Collection<ISomeOutput>; 
     } 
     private IMethodResult ExecuteSomeAction(ISomeInput2 input) 
     { 
      ServicesLogicContext logic = new ServicesLogicContext((MyType) Identifier); 
      return logic.ExecuteSomeAction(input); 
     } 
    } 
} 

namespace Domain.Logic 
{ 
    public sealed class ServicesLogicContext : ServicesLogicContextBase 
    { 
     public IList<ISomeOutput> GetSomeData(ISomeInput1 input) 
     { 
      DBServices services = DBServicesProvider.CreateServices(SomeIdentifier); 
      return DBServicesProvider.GetSomeData(input); 
     } 
     public IMethodResult ExecuteSomeAction(ISomeInput2 input) 
     { 
      DBServices services = DBServicesProvider.CreateServices(SomeIdentifier); 
      IMethodResult result = services.ExecuteSomeAction(input); 
      return result; 
     } 
    } 
} 

namespace Domain.Data 
{ 
    public abstract class DBServices : IServices 
    { 
     public virtual IList<ISomeOutput> GetSomeData(ISomeInput1 input) {...} 
     public virtual IMethodResult ExecuteSomeAction(ISomeInput2 input) {...} 
    } 

    public class DBServicesSpecific1 : DBServices 
    { 
     public override IList<ISomeOutput> GetSomeData(ISomeInput1 input) {...} 
     public override IMethodResult ExecuteSomeAction(ISomeInput2 input) {...} 
    } 

    public class DBServicesSpecific2 : DBServices 
    { 
     public override IList<ISomeOutput> GetSomeData(ISomeInput1 input) {...} 
     public override IMethodResult ExecuteSomeAction(ISomeInput2 input) {...} 
    } 

    public sealed class DBServicesProvider 
    { 
     public static DBServices CreateServices(MyType identifier) 
     { 
      DBServices result = null;  
      switch(identifier) 
      { 
       case MyType.Specific1: result = new DBServicesSpecific1(); break; 
       case MyType.Specific2: result = new DBServicesSpecific2(); break;  
      } 
      return result; 
     } 
    } 
} 
+1

+1感謝一些示例代碼,讓我深入研究! – JSprang 2010-10-27 21:12:24

+1

你說得對,模式不是特定的解決方案,而是解決各種問題的最佳實踐。具體的實現應該留給開發者。有一件事是,你的代碼似乎並沒有真正顯示一個工廠的例子(它確實顯示了一個類似於模式的服務定位器),並且它違背了SOL的S原則,你的ServicesLogicContext類似乎有多重責任。有趣的是,當討論模式時,一段代碼可能看起來像不同的模式給不同的人,但仍然是好的,正確的代碼。 – 2010-10-27 23:15:23