设计模式 - 六大设计原则之ISP(接口隔离原则)

2023-02-23 19:11:03 浏览数 (1)

文章目录

  • 概述
  • Case
  • Bad Impl
  • Better Impl

概述

接口隔离原则(Interface Segregation Principle, ISP),要求尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含相关的方法。

接口隔离是为了高内聚、低耦合。 在实际的开发中,通常都是先定义好需要开发的接口,并由各个服务去实现。 但是如果没有经过考虑和设计,很可能造成一个接口中包含了众多的接口方法,而这些接口并不一定在每一个类中都需要实现, 这样的接口很难维护, 也不易于扩展,每一次修改验证都有潜在的风险。

在具体应用接口隔离原则时, 应该根据以下几个规则进行考量

  • 接口尽量小,但应该有限度。 一个接口只服务于一个子模块或者业务逻辑
  • 为依赖接口的类定制服务, 只提供调用者需要的方法,屏蔽不需要的方法。
  • 提高内聚,减少对外交互,让接口用最少的方法完成最多的事情
  • 接口拆分的标准需要深入了解业务逻辑。

Case

毒药里的英雄, 射手,战士、刺客等等,都有对应的技能


Bad Impl

首先定义一个技能接口,所有的英雄都需要实现这个接口

代码语言:javascript复制
public interface ISkill {

    //灼日之矢
    void doArchery();

    // 隐袭
    void doInvisible();

    // 技能沉默
    void doSilent();

    // 眩晕
    void doVertigo();

}

【接口实现】

代码语言:javascript复制
ublic 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() {
        // 无此技能的实现
    }


}

后羿实现了三个技能, 最后一个眩晕技能无需实现(没有这功能)。


代码语言:javascript复制
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("廉颇的眩晕技能");
    }

}

廉颇实现了三个技能, 射箭技能无需实现(没有这功能)。


【单元测试】

代码语言:javascript复制
   @Test
    public void test_ISkill(){
        // 后裔
        HeroHouYi heroHouYi = new HeroHouYi();
        heroHouYi.doArchery();

        // 廉颇
        HeroLianPo heroLianPo = new HeroLianPo();
        heroLianPo.doInvisible();
    }

每个英雄里都有一个和自己无关的接口实现类,非常不符合设计模式,也不易于维护。 因为不仅无法控制外部的调用,还需要维护对应的文档来说明这个接口不需要实现。


Better Impl

接口隔离改善代码

按照接口隔离原则,应该在确保合理的情况下,把接口细分。 保证一个松散的结构,也就是把技能拆分出来,每个英雄都可以按需继承实现。

接下来分别定义4个技能接口

代码语言:javascript复制
public interface ISkillArchery {

    //灼日之矢
    void doArchery();

}

public interface ISkillInvisible {

    // 隐袭
    void doInvisible();

}

public interface ISkillSilent {

    // 技能沉默
    void doSilent();

}


public interface ISkillVertigo {

    // 眩晕
    void doVertigo();

}
代码语言:javascript复制
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("后裔的沉默技能");
    }

}
代码语言:javascript复制
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("廉颇的眩晕技能");
    }

}

【单元测试】

代码语言:javascript复制
 @Test
    public void test(){
        // 后裔
        HeroHouYi heroHouYi = new HeroHouYi();
        heroHouYi.doArchery();
        // 廉颇
        HeroLianPo heroLianPo = new HeroLianPo();
        heroLianPo.doInvisible();
    }

这样的实现方式就可以避免一些本身不属于自己的技能还需要不断的使用文档的方式进行维护,同时提高了代码的可靠性,可以降低开发成本和维护风险。

0 人点赞