工厂应该设置模型属性吗?

时间:2013-01-04 14:53:29

标签: c# asp.net solid-principles

作为整体S.O.L.I.D.编程工作的一部分,我创建了一个工厂界面&基础框架API中的抽象工厂。

人们已经开始重载工厂的Create方法。问题是人们正在使用模型属性重载Create方法(从而期望工厂填充它们)。

在我看来,不应该由工厂进行财产设置。我错了吗?

public interface IFactory
{
    I Create<C, I>();
    I Create<C, I>(long id); //<--- I feel doing this is incorrect

    IFactoryTransformer Transformer { get; }
    IFactoryDataAccessor DataAccessor { get; }
    IFactoryValidator Validator { get; }
}

更新 - 对于那些不熟悉SOLID原则的人,以下是其中一些原则:

单一责任原则
它声明每个对象应该只有一个责任,并且该责任应该完全由类

封装

开放/封闭原则
这个原则的含义是,当获得对需要添加到应用程序的功能的请求时,您应该能够在不修改旧类的情况下处理它,只需添加子类和新实现。

依赖性倒置原则
它说你应该解耦你的软件模块。要实现这一点,您需要隔离依赖项。

总体
我90%肯定我知道答案。但是,我想与已经使用SOLID的人进行一些很好的讨论。感谢您的宝贵意见。

更新 - 那么我认为SOLID工厂应该怎么办?

恕我直言,SOLID工厂提供适当的对象实例......但这样做会隐藏对象实例化的复杂性。例如,如果您有一个员工模型......您会要求工厂为您提供合适的模型。 DataAccessorFactory将为您提供正确的数据访问对象,ValidatorFactory将为您提供正确的验证对象等。

例如:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();
var dataAccessorLdap = Factory.DataAccessor.Create<LDAP, IEmployee>();
var dataAccessorSqlServer = Factory.DataAccessor.Create<SqlServer, IEmployee>();
var validator = Factory.Validator.Create<ExxonMobilEmployee, IEmployee>();

进一步举例,我们会...

var audit = new Framework.Audit(); // Or have the factory hand it to you
var result = new Framework.Result(); // Or have the factory hand it to you

// Save your AuditInfo
audit.username = 'prisonerzero';

// Get from LDAP (example only)
employee.Id = 10;
result = dataAccessorLdap.Get(employee, audit);
employee = result.Instance; // All operations use the same Result object

// Update model    
employee.FirstName = 'Scooby'
employee.LastName = 'Doo'

// Validate
result = validator.Validate(employee);

// Save to SQL
if(result.HasErrors)
     dataAccessorSqlServer.Add(employee, audit);

更新 - 为什么我坚持这种分离?

我觉得分离责任会产生较小的物体,较小的单元测试会增加可靠性和安全性。保养。我认识到它是以创建更多对象为代价的......但这就是SOLID工厂保护我的......它隐藏了收集和实例化所述对象的复杂性。

3 个答案:

答案 0 :(得分:6)

我会说它坚持DRY principle,只要它是简单的值布线,我就不会发现它存在问题/违规行为。而不是

var model = this.factory.Create();
model.Id = 10;
model.Name = "X20";

散布在您的代码库周围,将它放在一个地方几乎总是更好。未来的合同变更,重构或新要求将更容易处理。

值得注意的是,如果此类对象创建然后立即进行属性设置 common ,那么这是您的团队已经发展的模式,并且开发人员添加重载只是回应这个事实(值得注意的是,一个好的)。引入API以简化此过程是应该做的。

再次,如果它缩小到简单的任务(如你的例子),我会毫不犹豫地保持重载,特别是如果你经常注意到它。当事情变得更复杂时,它将是发现新模式的标志,也许你应该采用其他标准解决方案(例如builder pattern)。

答案 1 :(得分:2)

假设您的工厂界面是从应用程序代码(而不是基础结构组合根)使用的,它实际上代表了一个服务定位器,可以将其视为与依赖注入相关的反模式。另请参阅Service Locator: roles vs. mechanics

请注意以下代码:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();

只是语法糖。它不会消除对具体ExxonMobilEmployee实现的依赖。

您可能也对Weakly-typed versus Strongly-typed Message ChannelsMessage Dispatching without Service Location(这些界面如何违反SRP)以及Mark Seemann的其他出版物感兴趣。

答案 2 :(得分:0)

在Dependency Injection经历了大约6个月的经验后,我发现很少有工厂应该设置属性的案例:

  1. 如果设置器标记为internal,则预期属性仅由工厂设置一次。这通常发生在仅具有get个属性的接口上,其实现预期通过工厂创建。

  2. 当模型使用属性注入时。我很少看到使用属性注入的类(我也试图避免构建这些),但是当我确实看到一个,并且所需的服务只能在其他地方使用时,这是一个你别无选择的情况。

  3. 对于底线,请将public set个工厂留出。仅设置标记为internal的属性让客户决定在允许的情况下需要设置哪些属性。这将使您的工厂保持清洁不需要的功能。