我们正在构建一个ASP.NET项目,并将所有业务逻辑封装在服务类中。有些是在域对象中,但通常那些是相当贫血的(由于我们正在使用的ORM,这不会改变)。为了更好地启用单元测试,我们为每个服务定义接口并使用D.I ..例如。这里有几个接口:
IEmployeeService
IDepartmentService
IOrderService
...
这些服务中的所有方法基本上都是任务组,并且这些类不包含私有成员变量(除了对依赖服务的引用)。在我们担心单元测试之前,我们只是将所有这些类声明为静态并让它们直接相互调用。现在,如果服务依赖于其他服务,我们将设置这样的类:
public EmployeeService : IEmployeeService
{
private readonly IOrderService _orderSvc;
private readonly IDepartmentService _deptSvc;
private readonly IEmployeeRepository _empRep;
public EmployeeService(IOrderService orderSvc
, IDepartmentService deptSvc
, IEmployeeRepository empRep)
{
_orderSvc = orderSvc;
_deptSvc = deptSvc;
_empRep = empRep;
}
//methods down here
}
这实际上通常不是问题,但我想知道为什么不设置我们传递的工厂类呢?
即
public ServiceFactory
{
virtual IEmployeeService GetEmployeeService();
virtual IDepartmentService GetDepartmentService();
virtual IOrderService GetOrderService();
}
然后而不是打电话:
_orderSvc.CalcOrderTotal(orderId)
我们打电话给
_svcFactory.GetOrderService.CalcOrderTotal(orderid)
这种方法的缺点是什么?它仍然可以测试,它仍然允许我们使用D.I. (并通过工厂内外的D.I.处理外部依赖关系,如数据库上下文和电子邮件发件人),它消除了很多D.I.更多地设置和整合依赖项。
感谢您的想法!
答案 0 :(得分:4)
反对此的一个论点是它不会使您的依赖关系变得清晰。它表明你依赖“服务工厂中的一些东西”但不依赖于哪些服务。对于重构目的,确切地知道什么取决于什么是有帮助的。
依赖注入应该使这种事情变得容易,如果你使用了一个合适的框架 - 它应该只是创建正确的构造函数,定义实现哪个接口,并让它解决所有问题。
答案 1 :(得分:3)
这样的工厂本质上是服务定位器和I consider it an anti-pattern,因为它模糊了您的依赖关系,并且很容易违反Single Responsibility Principle(SRP)。
我们从构造函数注入中获得的众多优势之一就是it makes violations of the SRP so glaringly obvious。
答案 2 :(得分:2)
如果你的大多数类依赖于这三个接口,你可以传递一个将它们包装在一起的对象,但是:如果大多数类只依赖于其中的一个或两个,那么这不是一个好主意,因为这些类将具有访问他们不需要的对象,他们没有业务,一些程序员总是会调用他们不应该调用的代码,因为它可用。
顺便说一句,它不是工厂,除非你总是在Get [...] Service()方法中创建一个新对象,并且这样做只是为了传递一些方法是不好的。我只是将它称为ServiceWrapper并将它们转换为EmployeeService,DepartmentService和OrderService属性。