本文承接上文 使用面向对象重构之-继承中的抽象—模板方法。
新需求来了,员工需要有报销功能,并且基础员工和经理报销的逻辑不太一样。直接的做法是延续现在的继承结构,把不一样的部分使用虚函数完成抽象。
public class Employee
{
...
private void CommonSteps()
{
...
}
public void Claim()
{
CommonSteps();
ExtraSteps();
}
public virtual void ExtraSteps()
{
...
}
}
public class Manager : Employee
{
public override void ExtraSteps()
{
...
}
}
现在公司改制度了,报销是分类别的:基础报销,电话费。普通员工和经理的报销体制相同,而销售只可以报销电话费。如果不想改现在的结构,就至少要把Claim方法变成虚,因为销售的报销逻辑完全不同,Sales对象才能提供自己的实现。 public class Employee
{
private void CommonSteps()
{
// ...
}
public virtual void Claim()
{
CommonSteps();
ExtraSteps();
}
public virtual void ExtraSteps()
{
// ...
}
}
public class Manager : Employee
{
public override void ExtraSteps()
{
// ...
}
}
public class Sales : Employee
{
public override void ExtraSteps()
{
// do nothing
}
public override void Claim()
{
// sales Claim Logic
}
}
可以看到这条路明显已经走不下去了。因为sales已经继承到了它不需要的方法,因此继承关系不在成立。这时就需要使用接口来做更细粒度的抽象,从而支持更多扩展点。 实现就变成了:
public interface IClaim
{
void Claim();
}
public class StaffClaimProvider : IClaim
{
public void Claim()
{
throw new NotImplementedException();
}
}
public class SalesClaimProvider : IClaim
{
public void Claim()
{
throw new NotImplementedException();
}
}
public class Employee
{
private readonly IClaim _claimProvider;
public Employee()
{
}
public Employee(IClaim claimProvider)
{
_claimProvider = claimProvider;
}
public void Claim()
{
_claimProvider.Claim();
}
}
public class Manager : Employee
{
public Manager(IClaim claim)
: base(claim)
{
}
}
public class Sales : Employee
{
public Sales(IClaim claim)
: base(claim)
{
}
}
我们基本重写了几个model。首先创建了IClaim接口来完成报销行为的抽象,其次提供了基本报销和销售报销的实现,最后我们把报销函数从继承体系中拿出来,改为从构造函数注入。这样就达到了报销行为与员工继承体系分别扩展的目的。 本文介绍了当继承体系的抽象不足以支持程序扩展或继承关系不成立时,如何使用接口来完成更细粒度的抽象从而实现可持续扩展系统的构建。