接口隔离原则的定义是客户端不应该被迫依赖于它不使用的接口,一个类对另一个类的依赖应该建立在最小的接口上。接口隔离原则要求程序员尽量将庞大的接口拆分成更小而具体的接口。当然,接口不是越小越好,一个接口应该值服务于一个子模块或逻辑,更具业务需求设计接口,减少对外交互,提供调用者需要的方法,屏蔽不需要的方法。
未优化例子
以王者荣耀的英雄和技能为例,将英雄技能抽象为接口方法,两个英雄实现该接口。
public interface ISkill { //灼日之矢 void doArchery(); // 隐袭 void doInvisible(); // 技能沉默 void doSilent(); // 眩晕 void doVertigo(); }
public class HeroHouYi implements ISkill{ @Override public void doArchery() { System.out.println("后裔的灼日之矢"); } @Override public void doInvisible() { System.out.println("后裔的隐身技能"); } @Override public void doSilent() { System.out.println("后裔的沉默技能"); } @Override public void doVertigo() { // 无此技能的实现 } }
public class HeroLianPo implements ISkill{ @Override public void doArchery() { // 无此技能的实现 } @Override public void doInvisible() { System.out.println("廉颇的隐身技能"); } @Override public void doSilent() { System.out.println("廉颇的沉默技能"); } @Override public void doVertigo() { System.out.println("廉颇的眩晕技能"); } }
可以看到,对两个英雄类来说,都有不需要的方法,这样每个类的后续维护都要记得说明某方法不需要实现,对后期的维护造成不必要的麻烦,增加风险。
用接口隔离原则优化
public interface ISkillArchery { //灼日之矢 void doArchery(); } public interface ISkillInvisible { // 隐袭 void doInvisible(); } public interface ISkillSilent { // 技能沉默 void doSilent(); } public interface ISkillVertigo { // 眩晕 void doVertigo(); }
public class HeroHouYi implements ISkillArchery, ISkillInvisible, ISkillSilent { @Override public void doArchery() { System.out.println("后裔的灼日之矢"); } @Override public void doInvisible() { System.out.println("后裔的隐身技能"); } @Override public void doSilent() { System.out.println("后裔的沉默技能"); } }
public class HeroLianPo implements ISkillInvisible, ISkillSilent, ISkillVertigo { @Override public void doInvisible() { System.out.println("廉颇的隐身技能"); } @Override public void doSilent() { System.out.println("廉颇的沉默技能"); } @Override public void doVertigo() { System.out.println("廉颇的眩晕技能"); } }
优化后的代码中,将接口拆分成更小的接口,不同的类通过实现不同的接口组合实现需要的功能,且保证每个接口内的方法都是需要使用的,不会出现上面的问题。在这个例子中,将每个方法都拆分到单独的接口中,实际开发时拆分粒度以业务需要为准,可以简单地理解为单个接口内的方法都是绑定出现的,比如对于银行卡接口来说,增加余额和扣减余额一般都是绑定出现的,这时可以考虑将两个方法定义在同一接口中。
参考资料:《重学Java设计模式》