工厂模式和对象持久性

时间:2017-04-09 18:10:50

标签: c# factory-pattern

我在我的应用程序的一个部分中使用工厂设计模式,我注意到使用常规工厂模式每次都会创建一个新对象。我有一个场景,我需要多次在工厂类中迭代createinstance方法,并且每次创建一个新的使用者对象时。

在Program.cs中,我创建了人员列表,其中我键入了一些随机输入数据。基于对每个人的操作的代码应该动态地执行该类中的处理方法。这个逻辑似乎按照我的预期工作,但如果重复相同的操作,则会多次创建相同的对象。

为了解决这个问题,我修改了ActionFactory类(在下面的Modified Action Factory片段中显示),我在这里维护一个字典来保存为特定操作创建的实例。如果重复该操作,则不是创建新实例,而是从字典中获取先前创建的实例。这似乎修复了Output2图像中显示的问题。

但我想知道/从专业人员那里学习我在“改进的行动工厂”课程中所做的事情是否足够(或)是否有任何其他模式我应该使用而不是工厂设计模式来解决这类问题。为了维护单个对象,我能想到的另一种方法是在每个Action类中创建一个Singleton对象,但问题是如何从工厂类调用单例实例?因为工厂类总是调用createinstance并且不会调用单例实例。我是设计模式的新手,我很兴奋地了解它们并提高我的编码标准。提前致谢

以下是代码:

  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

修改后的行动工厂:

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

使用Modified Action Factory输出:

enter image description here

1 个答案:

答案 0 :(得分:2)

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不是那么容易创建的,例如,他们可能需要了解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());

一切都有设计模式,您应该找到适合您需求的设计模式。