16

作为整体SOLID编程工作的一部分,我在基础框架 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 原则的人,这里有一些:

单一职责原则
它指出每个对象都应该有单一职责,并且职责应该完全由类封装

Open/Closed 原则
这个原则的意思是当一个请求需要添加到你的应用程序中时,你应该能够在不修改旧类的情况下处理它,只需要添加子类和新的实现。

依赖倒置原则
它说你应该解耦你的软件模块。为此,您需要隔离依赖项。

总体而言:
我 90% 确定我知道答案。但是,我希望已经在使用 SOLID 的人进行一些很好的讨论。感谢您提出宝贵意见。

更新 - 那么我认为 SOLID 工厂应该做什么?

恕我直言,一个 SOLID 工厂提供适当的对象实例......但这样做的方式隐藏了对象实例化的复杂性。例如,如果您有一个 Employee 模型……您会要求工厂为您提供合适的模型。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 工厂保护我的原因……它隐藏了收集和实例化所述对象的复杂性。

4

3 回答 3

7

我会说它坚持DRY 原则,只要它是简单的值接线,我不认为它是问题/违规。而不是拥有

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

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

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

再说一次,如果它缩小到简单的分配(就像在你的例子中),我会毫不犹豫地保持重载,特别是如果它是你经常注意到的东西。当事情变得更复杂时,这将是发现新模式的标志,也许你应该求助于其他标准解决方案(例如构建器模式)。

于 2013-01-04T16:08:09.343 回答
2

假设您的工厂接口是从应用程序代码中使用的(而不是基础设施组合根),它实际上代表了一个服务定位器,可以将其视为依赖注入的反模式。另请参阅服务定位器:角色与机制

请注意,代码如下:

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

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

您可能还对弱类型与强类型消息通道无服务位置的消息调度(这些说明此类接口如何违反SRP)以及 Mark Seemann 的其他出版物感兴趣。

于 2013-01-04T23:04:38.180 回答
0

经过大约 6 个月的依赖注入经验,我只发现了少数几个工厂应该设置属性的情况:

  1. 如果 setter 标记为internal,并且属性预计仅由工厂设置一次。这通常发生在仅具有getter 属性的接口上,其实现预计将通过工厂创建。

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

最重要的是,将public setters 排除在工厂之外。仅设置标记为“internal让客户端决定需要设置哪些属性(如果允许)”的属性。这将使您的工厂清除不需要的功能。

于 2016-03-29T17:48:28.810 回答