Java设计模式:一、六大设计原则-05:接口隔离原则

一、定义接口隔离原则

  • 接口隔离原则Interface Segregation PrincipleISP
    • 客户端不应该被迫依赖于它不使用的方法
    • 另一个定义一个类对另一个类的依赖应该建立在最小的接口上
  • 接口隔离原则要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口让接口只包含客户感兴趣的方法。
  • 接口隔离是为了 高内聚、低耦合
    • 在实际的业务开发中通常会先定义好需要开发的接口并由各个服务类实现。
    • 但如果没有经过考虑和设计就很可能造成一个接口中包括众多的接口方法而这些接口并不一定在每一个类中都需要实现。
    • 这样的接口很难维护也不易于扩展每一次修改验证都有潜在的风险。
  • 在具体应用接口隔离原则时应该根据一下几个规则衡量。
    • 接口尽量小但是要有限度。一个接口只服务于一个子模块或业务逻辑。
    • 为依赖接口的类定制服务。只提供调用者需要的方法屏蔽不需要的方法。
    • 了解环境拒绝盲从。每个项目或产品都有选定的环境因素环境不同接口拆分的标准就不同要深入了解业务逻辑。
    • 提高内聚减少对外交互。让接口用最少的方法完成最多的事情。

二、模拟场景接口隔离原则

  • 《王者荣耀》里有很多英雄可以分为射手、战士、刺客等每个英雄有三种技能。
  • 这些技能该如何定义让每个英雄实现相应的技能效果呢

三、违背方案接口隔离原则

3.1 工程结构

design-1.5-0
|——src
    |——main
        |--java
            |--com.lino.design
                |--HeroHouYi.java
                |--HeroLianPo.java
                |--ISkill.java
    |——test
        |--java
            |--com.lino.design.test
                |--ApiTest.java

3.2 英雄技能调用

3.2.1 英雄技能接口

ISkill.java

package com.lino.design;

/**
 * @description: 英雄技能接口
 */
public interface ISkill {

    /**
     * 射箭
     */
    void doArchery();

    /**
     * 隐袭
     */
    void doInvisible();

    /**
     * 沉默
     */
    void doSilent();

    /**
     * 眩晕
     */
    void doVertigo();
}
  • 定义一个技能接口实现的英雄都需要实现这个接口进而实现自己的技能。
  • 这里提供了四个技能的接口包括射箭、隐袭、沉默、晕眩每个英雄都实现这个接口。接下来实现两个英雄后裔和廉颇。

3.2.2 英雄后裔

HeroHouYi.java

package com.lino.design;

/**
 * @description: 英雄后裔
 */
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() {
        // 无此技能的实现
    }
}
  • 在英雄后裔的类中实现了三个技能最后一个晕眩的技能是不需要实现的。

3.2.3 英雄廉颇

HeroLianPo.java

package com.lino.design;

/**
 * @description: 英雄廉颇
 */
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("廉颇的眩晕技能");
    }
}
  • 在英雄廉颇的类中同样只实现了三个技能有一个射箭的技能没有实现。

3.3 单元测试

ApiTest.java

@Test
public void test_ISKill() {
    // 后裔
    HeroHouYi heroHouYi = new HeroHouYi();
    heroHouYi.doArchery();

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

测试结果

后裔的灼日之矢
廉颇的隐身技能
  • 综上每个英雄的实现类里都有一个和自己无关的接口实现类非常不符合设计模式也不易于维护。
  • 因为不仅无法控制外部的调用还需要维护对应的文档来说明这个接口不需要实现。如果由更多这样的接口就会变得非常麻烦。

四、改善代码接口隔离原则

4.1 工程结构

design-1.5-1
|——src
    |——main
        |--java
            |--com.lino.design
                |--impl
                |   |-HeroHouYi.java
                |   |-HeroLianPo.java
                |--ISkillArchery.java
                |--ISkillInvisible.java
                |--ISkillSilent.java
                |--ISkillVertigo.java
    |——test
        |--java
            |--com.lino.design.test
                |--ApiTest.java

4.2 英雄分配英雄技能

  • 按照接口隔离原则的约定应该在确保合理的情况下把接口细分。保证一个松散的结构也就是把技能拆分出来每个英雄都可以按需继承实现。
  • 接下来分别定义四个技能接口包括
    • 射箭ISkillArchery
    • 隐身ISkillInvisible
    • 沉默ISkillSilent
    • 晕眩ISkillVertigo

4.2.1 射箭接口

ISkillArchery.java

package com.lino.design;

/**
 * @description: 射箭技能
 */
public interface ISkillArchery {

    /**
     * 射箭
     */
    void doArchery();
}

4.2.2 隐袭接口

ISkillInvisible.java

package com.lino.design;

/**
 * @description: 影袭技能
 */
public interface ISkillInvisible {

    /**
     * 隐袭
     */
    void doInvisible();
}

4.2.3 沉默

ISkillSilent.java

package com.lino.design;

/**
 * @description: 沉默技能
 */
public interface ISkillSilent {

    /**
     * 沉默
     */
    void doSilent();
}

4.2.4 晕眩

ISkillSilent.java

package com.lino.design;

/**
 * @description: 晕眩技能
 */
public interface ISkillVertigo {

    /**
     * 眩晕
     */
    void doVertigo();
}

4.2.5 英雄后裔的实现

HeroHouYi.java

package com.lino.design.impl;

import com.lino.design.ISkillArchery;
import com.lino.design.ISkillInvisible;
import com.lino.design.ISkillSilent;

/**
 * @description: 英雄后裔
 */
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("后裔的沉默技能");
    }
}

4.2.6 英雄廉颇的实现

HeroLianPo.java

package com.lino.design.impl;

import com.lino.design.ISkillInvisible;
import com.lino.design.ISkillSilent;
import com.lino.design.ISkillVertigo;

/**
 * @description: 英雄廉颇
 */
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("廉颇的眩晕技能");
    }
}

4.3 单元测试

ApiTest.java

@Test
public void test_ISKill() {
    // 后裔
    HeroHouYi heroHouYi = new HeroHouYi();
    heroHouYi.doArchery();

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

测试结果

后裔的灼日之矢
廉颇的隐身技能
  • 现在可以看到这两个英雄的类都按需实现了自己需要的技能接口。
  • 这样的实现方式就可以避免一些本身不属于自己的技能还需要不断地用文档的方式进行维护同时提高了代码的可靠性在别人接手或者修改时可以降低开发成本和维护风险。
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java

“Java设计模式:一、六大设计原则-05:接口隔离原则” 的相关文章