使用工厂模式保存数据?

发布于 2024-09-29 00:15:15 字数 532 浏览 8 评论 0原文

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

以前,我会做类似以下的事情,其中​​有一个经理类可以构建并保存一辆汽车。这里没有依赖注入,并且是一个糟糕的实现,特别是在尝试进行单元测试时。

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

    public static void SaveCar(Car car) { }
}

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

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

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

I've been becoming more familiar with the Factory Pattern (along with Strategy Pattern) and what a great benefit the pattern can have. However, I've been struggling with the following situation:

Previously, I would have done something like the following, where there's a manager class that would build and save a Car. There's no dependency injection here and is a poor implementation, especially when trying to unit test.

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

    public static void SaveCar(Car car) { }
}

I see now how I could have different Factories that build cars for me, whether it be from a database, or wherever! This is great! So, here's my questions:

Q1: It's my understanding that Factories should only build objects, is that correct? If so, what about my second question?

Q2: If I'm following the Factory Pattern for building my objects, how should I go about saving my objects? Is there a different pattern for this, or am I not completely understanding the Factory Pattern?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

尬尬 2024-10-06 00:15:15

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

存储库模式是一种持久化模式,应用于将对象保存到某些持久化机制或检索数据来自持久化机制。根据 Martin Fowler 的说法,这实际上是一种企业模式,应该采用与典型设计模式不同的方式。

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

The Factory pattern is supposed to help with the creation of objects. That is why it is categorized as a "Creation" pattern. To answer your first question, it should not be used to persist objects.

The Repository pattern is a persistence pattern that should be used for saving objects to some persistence mechanism or retrieving data from a persistence mechanism. This is actually, according to Martin Fowler, an enterprise pattern which should be approached different than the typical design pattern.

When thinking about your question, you want to look at the S principle in SOLID which states that a class should have a single responsibility, which means that it should have a single reason to change. In this case, when talking about a object that creates objects as well as saves (persists) them, you have a class that has two reasons to change. Now, it might look like it could be a single responsibility because a Repository can retrieve and save objects into your application and the retrieve can look like a factory (and often is a factory object within the repository), but in what you're describing, your object has one too many responsibilities.

私野 2024-10-06 00:15:15

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

Factory should not be saving data. A Data Access Object (DAO) or table mapper would be a better idea.

一紙繁鸢 2024-10-06 00:15:15

一切都取决于您的需求以及您想要如何做事情,模式是没有标准的实践,它们鼓励代码重用,模式不是一成不变的。那么,为什么不使用工厂模式来使对象持久化呢?这就是我使用这种模式来解决从不同数据库读取数据/向不同数据库写入数据的问题的方式,也许这不是使用该模式的更好形式,但它目前正在工作,是可扩展的,分布在层之间,并且几乎大家都能理解:

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

All depends on your needs and how you want to do the things, patterns are practices no standards, they encourage for code reuse, patterns are not grabbed on stone. So, why should you not use Factory Pattern to make objects persistence?. This is how I have used such pattern for solve the problem to read/write data from/to different databases, maybe this is not the better form of using the pattern but it is currently working, is extensible, is distributed among layers, and almost everybody can understand it:

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;
        }
    }
}
紫南 2024-10-06 00:15:15

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

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

您所发布的代码提到的唯一问题是单元测试并不容易。使类更具可测试性的一种解决方案是反转它们的依赖关系。因此,我将开始查看该类所依赖的其他类,并开始创建这些可注入的依赖项。作为起点,我建议您阅读依赖倒置/控制倒置。

In general, I think you are approaching this from the wrong angle.

You need to identify the problem you are trying to solve, and then look for solutions that fit that problem. It sounds to me more like you have discovered a certain pattern, and then are trying to apply it to every problem you encounter.

The only problem you mention with the code you posted is that it's not easy to unit test. One solution to making classes more testable is to invert their dependencies. So I would start looking at what other classes this class depends on, and start making those injectable dependencies. As a starting point, I would recommend you read up on dependency inversion/inversion of control.

疯了 2024-10-06 00:15:15

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

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

Q1 - Yes, Factory pattern should be ideally used for creation of objects. So, you can create your Car object using the factory pattern.

Q2 - For saving your car object you should not use the factory pattern. Decouple the Car object creation and saving the car object. And, it is difficult to suggest a design pattern to save your car object without understanding the requirements accurately. In my opinion, if you just need to save your car objects then all you perhaps need is a save method in your car manager class. Do not over use design patterns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文