使用接口和抽象类的总的原则如下:
1.用接口作为系统和外界交互的窗口。站在外界使用者(另一个系统)的角度,接口向使用者承诺系统能够提供哪些服务;站在系统的角度,接口指定系统必须实现哪些服务。接口是系统中最高层次的抽象类型。这里的系统即可以指整个大系统,也可以指完成特定功能的相对独立的局部系统。
2.由于外界使用者依赖系统的接口,并且系统内部会实现接口,因此接口本身必须十分稳定,接口一旦制定,就不允许随意修改,否则会对外界使用者和系统内部都会造成影响。
3.用抽象类来定制系统中的扩展点。可以把抽象类看做介于“抽象”和“实现”之间的半成品,抽象类力所能及地完成了部分实现,但还有一些功能有待于它的子类去实现。
与接口有关的设计模式
1.定制服务模式
当一个系统能对外提供多种类型的服务时,一种方式是设计粗粒度的接口,把所有的服务放在一个接口中声明,这个接口臃肿庞大,所有的使用者都访问同一个接口。还有一种方式是设计精粒度的接口,对服务精心分类,把相关的一组服务放在一个接口中,通过对接口的继承,可以派生出新的接口,针对使用者的需求提供特定的接口。第二种方式使得系统更加容易维护,向使用者提供接口是一种承诺,接口一旦提供,就很难撤回。作为软件供应商,没有人愿意做出过多的承诺,尤其是不必要的承诺,过多的承诺会给系统的维护造成不必要的负担。精粒度的接口可以减轻软件提供商的软件维护成本。
2.适配器模式
松耦合的系统之间通过接口来交互,当两个系统之间的接口不匹配时,就需要用适配器来把一个系统的接口转换为与另一个系统匹配的接口。可见适配器的作用是进行接口的转换。
在面向对象领域,也采用适配器模式来进行接口的转换。适配器模式有两种实现方式。
1.继承实现方式
public interface SourceIFC{
public int add(int a,int b);
}
public interface TargetIFC{
public int addOne(int a);
public int add(int a,int b);
}
public class SourceImpl implements SourceIFC{
public int add(int a,int b){
return a+b;
}
}
//这个类为适配器
public class TargetImpl extends SourceImpl implements TargetIFC{
public int addOne(int a){
return add(a,1);
}
}
2.组合实现方式
public class TargetImpl implements TargetIFC{
private SourceIFC source;
public TargetImpl(SourceIFC source){
this.source=source;
}
public int add(int a,int b){
return source.add(a,b);
}
public int addOne(int a){
return source.add(a,1);
}
}
TargetImpl为适配器,它实现了TargetIFC接口,并且包装了SourceIFC的实现类,从而能重用SourceImpl类的add()方法。TargetImpl类对SourceImpl类进行了包装,从而生成新的接口。采用这种实现方式的适配器模式也称为包装类模式。
3.代理模式
代理模式可以运用到面向对象的软件开发系统领域,它的特征是:代理类和委托类有同样的接口。代理类主要负责为委托类预处理消息、过滤消息及把消息转发给委托类等,代理类与委托类之间为组合关系(一个代理类可以代理几个委托类)。
4.标识类型模式
该类型的接口不包含任何方法,它仅表示一种抽象类型,所有实现该接口的类都可以上转型为该接口。
5.常量接口模式
在一个软件系统中会使用一些常量,一种流行的做法是把相关的常量放在一个专门的常量接口中定义。