2017-04-09 161 views
1

我在我的應用程序的某個段中使用了工廠設計模式,並且我注意到使用常規工廠模式每次都會創建一個新對象。我有一個場景,我需要多次迭代工廠類中的createinstance方法,並且每次創建一個新的使用者對象時。工廠模式和對象持久化

在Program.cs中,我創建了人員列表,其中我輸入了一些隨機輸入數據。基於每個人的行爲的代碼應該動態地執行該類中的過程方法。這個邏輯看起來像我所期望的那樣工作,但是如果重複相同的動作,則多次創建相同的對象。

爲了解決這個問題,我修改了ActionFactory類(顯示在下面的Modified Action Factory代碼片段中),我在這裏維護一個字典來保存爲特定操作創建的實例。如果動作重複,那麼不是創建一個新實例,而是從字典中獲取以前創建的實例。這似乎解決了Output2映像中顯示的問題。

但我想知道/從專業人士學習如果我在「修改的行動工廠」類中所做的工作是否足夠(或)是否有任何其他模式應該使用而不是工廠設計模式來解決這類問題。對於維護單個對象,我能想到的另一種方法是在每個Action類中創建一個Singleton對象,但問題在於如何從工廠類調用單例實例?因爲工廠類總是調用createinstance,並且不會調用singleton實例。我對設計模式很陌生,我很興奮能夠更多地瞭解它們並提高我的編碼標準。在此先感謝

下面是代碼:

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<Person> ListofPeople = new List<Person>(); 

     Person p1 = new Person() {Name = "P1", State = "CA", Action = "Add"}; 

     ListofPeople.Add(p1); 

     Person p2 = new Person() { Name = "P2", State = "NJ", Action = "Add" }; 

     ListofPeople.Add(p2); 

     Person p3 = new Person() { Name = "P3", State = "VA", Action = "Update" }; 

     ListofPeople.Add(p3); 

     Person p4 = new Person() { Name = "P4", State = "VA", Action = "Update" }; 

     ListofPeople.Add(p4); 


     Person p5 = new Person() { Name = "P5", State = "VA", Action = "Update" }; 

     ListofPeople.Add(p5); 


     Person p6 = new Person() { Name = "P6", State = "VA", Action = "Delete" }; 

     ListofPeople.Add(p6); 


     ActionFactory factory= new ActionFactory(); 

     foreach (var person in ListofPeople) 
     { 
      IAction action = (IAction) factory.CreateInstance(person.Action.ToLower()); 

      action.Process(); 

     } 
     Console.ReadKey(); 


    } 
} 

public class Person 
{ 
    public string Name { get; set; } 
    public string State { get; set; } 
    public string Action { get; set; } 

} 

ActionFactory:

public class ActionFactory 
{ 
    Dictionary<string, Type> actions; 

    public ActionFactory() 
    { 
     LoadTypesICanReturn(); 
    } 

    public object CreateInstance(string actionName) 
    { 
     Type t = GetTypeToCreate(actionName); 

     if (t == null) 
      return null; 

     var actionProcessor = Activator.CreateInstance(t) as IAction; 

     return actionProcessor; 
    } 

    Type GetTypeToCreate(string actionName) 
    { 
     foreach (var action in actions) 
     { 
      if (action.Key.Contains(actionName)) 
      { 
       return actions[action.Key]; 
      } 
     } 

     return null; 
    } 

    void LoadTypesICanReturn() 
    { 
     actions = new Dictionary<string, Type>(); 

     Type[] typesInThisAssembly = Assembly.GetExecutingAssembly().GetTypes(); 

     foreach (Type type in typesInThisAssembly) 
     { 
      if (type.GetInterface(typeof(IAction).ToString()) != null) 
      { 
       actions.Add(type.Name.ToLower(), type); 
      } 
     } 
    } 
} 

IAction:

public interface IAction 
{ 
    void Process(); 
} 

Add.cs

public class Add: IAction 
{ 

    public Add() 
    { 
     Console.WriteLine("add constructor..."); 
    } 

    #region IAction Members 

    public void Process() 
    { 
     Console.WriteLine("Add Processor...."); 
    } 

    #endregion 
} 

Update.cs

public class Update: IAction 
{ 
    public Update() 
    { 
     Console.WriteLine("Update constructor..."); 
    } 


    public void Process() 
    { 
     Console.WriteLine("Update Processor..."); 
    } 
} 

Delete.cs

public class Delete : IAction 
{ 

    public Delete() 
    { 
     Console.WriteLine("Delete Constructor..."); 
    } 



    #region IAction Members 

    public void Process() 
    { 
     Console.WriteLine("Delete Processor..."); 
    } 

    #endregion 
} 

控制檯輸出顯示的次數進行IAction消費者類被實例化

輸出數:

enter image description here

Mo dified行動廠:

public class ActionFactory 
{ 
    Dictionary<string, Type> actions; 

    private Dictionary<Type, IAction> actionInstances; 

    public ActionFactory() 
    { 

     actionInstances = new Dictionary<Type, IAction>(); 
     LoadTypesICanReturn(); 
    } 

    public object CreateInstance(string actionName) 
    { 
     Type t = GetTypeToCreate(actionName); 

     if (t == null) 
      return null; 

     if (actionInstances.ContainsKey(t)) 

      return actionInstances[t]; 

     else 
     { 
      var actionProcessor = Activator.CreateInstance(t) as IAction; 

      LoadIAction(t, actionProcessor); 

      return actionProcessor; 
     } 


    } 


    private void LoadIAction(Type t, IAction actionProcessor) 
    { 

     if (!actionInstances.ContainsKey(t)) 
     { 
      actionInstances.Add(t, actionProcessor); 
     } 
    } 

    Type GetTypeToCreate(string actionName) 
    { 
     foreach (var action in actions) 
     { 
      if (action.Key.Contains(actionName)) 
      { 
       return actions[action.Key]; 
      } 
     } 

     return null; 
    } 

    void LoadTypesICanReturn() 
    { 
     actions = new Dictionary<string, Type>(); 

     Type[] typesInThisAssembly = Assembly.GetExecutingAssembly().GetTypes(); 

     foreach (Type type in typesInThisAssembly) 
     { 
      if (type.GetInterface(typeof(IAction).ToString()) != null) 
      { 
       actions.Add(type.Name.ToLower(), type); 
      } 
     } 
    } 
} 

輸出與修正動作廠:

enter image description here

回答

1

Factory設計模式來緩解對象的創建,通常當你不知道類型創建,它將在運行時提供。
有時,也可能是因爲它們具有依賴性,並且您想要抽象依賴關係創建,或者僅僅因爲您想要完成某些操作。

在你的情況,AddUpdateDelete是通常由一些第三方,而不是數據類型本身調用,用如上述@sokohavi指定的方法。

您的情況可以通過Command Design Pattern來處理。假設你想加載一堆命令(又名:Add Person X, Update Person Y, Delete Person Z),並且你想緩衝它們以備將來使用。

abstract class PersonCommand 
{ 
    Person Person { protected get; } // you can call this payload, or person, w/e 

    PersonCommand(Person person) 
    { 
     Person = person; 
    } 

    public abstract void Apply(); // can be called Execute or Process as well, or w/e. problem domain. 
} 

然後,你必須爲每個命令的實現:

class AddCommand : PersonCommand 
{ 
    AddCommand(Person person) : base(person) { } 
    public override void Apply() 
    { 
     // send REST PUT request, add person to DB, whatever you want to do here. 
    } 
} 

class UpdateCommand : PersonCommand 
{ 
    UpdateCommand(Person person) : base(person) { } 
    public override void Apply() 
    { 
     // send REST POST request, update person in DB, whatever you want to do here. 
    } 
} 

class DeleteCommand : PersonCommand 
{ 
    DeleteCommand(Person person) : base(person) { } 
    public override void Apply() 
    { 
     // send REST DELETE request, remove person from DB, whatever you want to do here. 
    } 
} 

當你有了這個,你可以做到以下幾點:

var commandsToExecute = new List<PersonCommand>(); 

commandsToExecute.Add(new AddCommand(new Person { Name = "asd", State = "CA" })); 

commandsToExecute.Add(new UpdateCommand(new Person { Name = "barry", State = "CA" })); 

commandsToExecute.Add(new DeleteCommand(new Person { Name = "barry", State = "CA" })); 

commandsToExecute.ForEach(cmd => cmd.Apply()); 

現在,這是一個基本的你可以做什麼的例子。 也許,在某些情況下,Command s不是很容易創建的,例如,它們可能需要了解有關REST請求的服務端點。

爲此,一個CommandFactory可以創建,則可以通過動作名稱辦理創作:

class CommandFactory 
{ 
    private readonly Dictionary<string, Func<Person, PersonCommand>> creationFuncs; 

    CommandFactory(string backendUrl) 
    { 
     creationFuncs = new Dictionary<string, Func<Command, Person>>(); 

     creationFuncs.Add("add", (person) => return new AddCommand(backendUrl, person)); 
     creationFuncs.Add("update", (person) => return new UpdateCommand(backendUrl, person)); 
     creationFuncs.Add("delete", (person) => return new DeleteCommand(backendUrl, person)); 
    } 

    PersonCommand Create(string action, Person person) 
    { 
     // validation can be added here 
     return creationFuncs[action](person); 
    } 
} 

而且用法是:

的一切,你應該
var factory = new CommandFactory("http://localhost:4200/person/"); 

var commandsToExecute = new List<PersonCommand>(); 

commandsToExecute.Add(factory.Create("add", new Person { Name = "asd", State = "CA" })); 

commandsToExecute.Add(factory.Create("update", new Person { Name = "barry", State = "CA" })); 

commandsToExecute.Add(factory.Create("delete", new Person { Name = "barry", State = "CA" })); 

commandsToExecute.ForEach(cmd => cmd.Apply()); 

有設計模式找到適合您需求的產品。

+0

謝謝Giora。它爲我所遇到的問題提供了一個新的解決方案。我會在我的設計中嘗試你的解決方案。 – marak