【问题标题】:Saving Data with the Factory Pattern?使用工厂模式保存数据?
【发布时间】:2010-10-27 16:58:27
【问题描述】:

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

以前,我会做类似以下的事情,其中​​有一个可以构建和保存汽车的管理器类。这里没有依赖注入,实现起来很糟糕,尤其是在尝试进行单元测试时。

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

    public static void SaveCar(Car car) { }
}

我现在明白了如何拥有不同的 Factories 来为我制造汽车,无论是来自数据库还是其他任何地方!这很棒!所以,这是我的问题:

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

Q2:如果我遵循工厂模式来构建我的对象,我应该如何保存我的对象?是否有不同的模式,或者我没有完全理解工厂模式?

【问题讨论】:

  • 工厂不应该真正构建对象——它们的目的是从一组相关的对象类型中选择正确的具体类型,这些对象类型都继承自同一个基础。你确定你指的是工厂而不是建造者吗?

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


【解决方案1】:

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

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

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

【讨论】:

  • 感谢@Dave White。看完你的帖子后,我看了一个关于 Repository 模式的 Pluralsight 视频,这就是我想要的。感谢您的回复!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    一切都取决于您的需求以及您想如何做事,模式是没有标准的实践,它们鼓励代码重用,模式不是一成不变的。那么,为什么不使用 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;
            }
        }
    }
    

    【讨论】:

    • 你说得对,模式不是特定的解决方案,而是解决各种问题的最佳实践。具体实现应该留给开发者。但有一件事是,您的代码似乎并没有真正显示工厂示例(它确实显示了类似模式的服务定位器),并且它违反了 SOLID 中的 S 原则,您的 ServicesLogicContext 类似乎有多种职责。有趣的是,在讨论模式时,一段代码对于不同的人来说可能看起来像不同的模式,但仍然是好的、正确的代码。
    【解决方案4】:

    总的来说,我认为你是从错误的角度来处理这个问题的。

    您需要确定您要解决的问题,然后寻找适合该问题的解决方案。在我看来,这更像是您发现了某种模式,然后尝试将其应用于遇到的每个问题。

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-18
        • 1970-01-01
        • 2017-10-30
        • 2016-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多