使用继承模板化服务依赖注入

service dependency injection templated using inheritance

使用模板模式(继承)为 class 注入依赖项的优缺点是什么。

假设我正在创建一堆业务服务 classes,例如,作为 SecurityService 实现的 ISecurityService。

而且,如果我知道所有业务服务(包括 ISecurityService)will/should 都依赖于 IBusinessContext 来获取服务上下文信息,我可以使用模板模式(使用继承)来 achieve/enforce 吗?

方法 #1:

public interface IBusinessContext
{
   public int Property { get; }
}

public interface IService
{
   public IBusinessContext Context { get; }
}

public abstract class ServiceBase : IService
{
   public IBusinessContext Context { get; }

   public ServiceBase(IBusinessContext context) { _context = context; }
}

public interface IBusinessServiceN : IService
{
   public void DoSomething();
}

public class BusinessServiceN : ServiceBase, IBusinessServiceN
{
   public SecurityService(IBusinessCnotext context)
          : base(context) { }

   public void DoSomething() { }
}

方法 #2:

public interface IBusinessContext
{
   public int Property { get; }
}

public interface IBusinessServiceN
{
   public void DoSomething();
}

public class BusinessServiceN : IBusinessServiceN
{
   private IBusinessContext _context;

   public SecurityService(IBusinessCnotext context) { _context = context; }

   public void DoSomething() { }
}

首选哪种方法,为什么?

第 2 个,因为为什么服务将 IBusinessContext 公开为 public 属性 是有意义的?它没有。这是它的依赖项之一,不需要通过接口公开,甚至不需要在具体 class.

上公开

消费 IService 的合同不/不应包括创建具体 class 以实现 IService 的合同。如果我可以在没有 IBusinessContext 实例的情况下实现 IService,那是一件好事,尤其是在编写单元测试和模拟 IService 时。或者,如果我的 IService 实现需要一个 ICompleteContext 而不是包含一个 IBusinessContext,又不应该像在 #1.

中那样用某些接口人为地限制它怎么办?

这完全取决于您的要求。除非您的摘要中有可重用代码 class,否则方法 #1 不会增加任何好处。

当您有一个通用的工作流并且您确定该工作流不会改变时,模板方法模式真正发挥作用;虽然子实现可能会改变某些步骤,但它们可能不会改变工作流结构。

所以假设在您的 DoSomething 方法中您有一个 "strict" 工作流程,其中一些步骤与继承 classes:

相同
public virtual void DoSomething() {
        DoSomethingFirst(); // -> common to all classes
        DoSomethingAfter(); //-> each class has unique implementation
}

你的基础 class 可以采用以下形式:

 public abstract class ServiceBase : IService
{
    public IBusinessContext Context { get; }

    public ServiceBase(IBusinessContext context) { Context = context; }

    public void DoSomethingFirst() {
        // common implementation here
    }

    public abstract void DoSomethingAfter();

    public virtual void DoSomething() {
        DoSomethingFirst(); 
        DoSomethingAfter();
    }
}

还有你的具体 class:

 public class BusinessServiceN : ServiceBase, IBusinessServiceN
{
    public BusinessServiceN(IBusinessContext context)
           : base(context) { }

    public override void DoSomethingAfter()
    {
        //Your custom implementation here
    }
}

如您所见,您的 DoSomething() 方法和 shared/reusable DoSomethingFirst() 方法中有一个强制结构。