开发者

Saving Data with the Factory Pattern?

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 som开发者_如何学运维ething 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?


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.


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


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜