使用工厂模式保存数据?

时间:2010-10-27 16:58:27

标签: c# design-patterns dependency-injection factory-pattern strategy-pattern

我越来越熟悉工厂模式(以及战略模式)以及模式可以带来的巨大好处。但是,我一直在努力应对以下情况:

以前,我会做类似以下的事情,其中​​有一个经理类可以构建和保存汽车。这里没有依赖注入,并且执行效果很差,尤其是在尝试进行单元测试时。

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

    public static void SaveCar(Car car) { }
}

我现在看到我可以为我制作不同的Factories,无论是来自数据库,还是来自哪里!这很棒!所以,这是我的问题:

Q1:我的理解是Factories只应该构建对象,这是正确的吗?如果是这样,我的第二个问题呢?

Q2:如果我按照工厂模式构建我的对象,我应该如何保存我的对象?对此有不同的模式,还是我不完全理解工厂模式?

5 个答案:

答案 0 :(得分:15)

Factory模式应该有助于创建对象。这就是为什么它被归类为“创造”模式。要回答你的第一个问题,它不应该用于持久化对象。

Repository pattern是一种持久性模式,应该用于将对象保存到某种持久性机制或从持久性机制中检索数据。事实上,根据Martin Fowler的说法,企业模式应该与典型的设计模式不同。

在考虑你的问题时,你想看看S principle in SOLID,它指出一个班级应该只有一个责任,这意味着它应该有一个改变的理由。在这种情况下,当谈论创建对象以及保存(持久化)对象的对象时,您有一个有两个原因需要更改的类。现在,看起来它可能是一个单一的责任,因为Repository可以检索并将对象保存到您的应用程序中,并且检索可以看起来像工厂(并且通常是存储库中的工厂对象),但是在您所描述的内容中,你的对象有太多的责任。

答案 1 :(得分:3)

工厂不应该保存数据。数据访问对象(DAO)或表映射器将是一个更好的主意。

答案 2 :(得分:2)

一切都取决于你的需求和你想要做的事情,模式是没有标准的做法,他们鼓励代码重用,模式不是一蹴而就。那么,为什么不使用 Factory Pattern 来使对象持久化?这就是我使用这种模式来解决从/向不同数据库读/写数据的问题,也许这不是使用模式的更好形式,但它目前正在工作,可扩展,分布在层之间,几乎每个人都能理解:

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

答案 3 :(得分:1)

一般来说,我认为你是从错误的角度接近这个。

您需要确定要解决的问题,然后寻找适合该问题的解决方案。听起来我更像是你发现了某种模式,然后试图将它应用到你遇到的每一个问题上。

您在发布的代码中提到的唯一问题是单元测试并不容易。使类更易测试的一种解决方案是反转它们的依赖关系。所以我会开始研究这个类所依赖的其他类,并开始制作那些可注入的依赖项。作为一个起点,我建议你阅读依赖倒置/控制反转。

答案 4 :(得分:1)

Q1 - 是的,工厂模式应该理想地用于创建对象。因此,您可以使用工厂模式创建Car对象。

Q2 - 为了保存您的汽车对象,您不应使用工厂模式。解耦Car对象创建并保存car对象。而且,如果不准确地理解要求,很难建议设计模式来保存您的汽车对象。在我看来,如果您只需要保存您的汽车对象,那么您可能需要的只是汽车经理类中的保存方法。不要过度使用设计模式。