我越来越熟悉工厂模式(以及战略模式)以及模式可以带来的巨大好处。但是,我一直在努力应对以下情况:
以前,我会做类似以下的事情,其中有一个经理类可以构建和保存汽车。这里没有依赖注入,并且执行效果很差,尤其是在尝试进行单元测试时。
public class CarManager
{
public static Car GetCarFromDatabase(int carId) { return new Car(); }
public static void SaveCar(Car car) { }
}
我现在看到我可以为我制作不同的Factories
,无论是来自数据库,还是来自哪里!这很棒!所以,这是我的问题:
Q1:我的理解是Factories
只应该构建对象,这是正确的吗?如果是这样,我的第二个问题呢?
Q2:如果我按照工厂模式构建我的对象,我应该如何保存我的对象?对此有不同的模式,还是我不完全理解工厂模式?
答案 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对象。而且,如果不准确地理解要求,很难建议设计模式来保存您的汽车对象。在我看来,如果您只需要保存您的汽车对象,那么您可能需要的只是汽车经理类中的保存方法。不要过度使用设计模式。