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

简介: 设计模式六大原则(四)----接口隔离原则

一. 接口隔离原则的定义


Clients should not be forced to depend upon interfaces that they don't use.


客户端只依赖于它所需要的接口;它需要什么接口就提供什么接口,把不需要的接口剔除掉。

The dependency of one class to another one should depend on the smallest possible interface.


类间的依赖关系应建立在最小的接口上。

也就是说: 接口尽量细化,接口中的方法尽量少


二. 接口隔离原则和单一职责原则



从功能上来看,接口隔离原则和单一职责原则都是为了提高类的内聚, 降低类之间的耦合, 体现了封装的思想。但二者还是有区别的。


(1)从原则约束来看: 接口隔离原则更关注的是接口依赖程度的隔离;而单一职责原则更加注重的是接口职责的划分。

(2)从接口的细化程度来看: 单一职责原则对接口的划分更加精细,而接口隔离原则注重的是相同功能的接口的隔离。接口隔离里面的最小接口有时可以是多个单一职责的公共接口。


(3)单一职责原则更加偏向对业务的约束: 接口隔离原则更加偏向设计架构的约束。这个应该好理解,职责是根据业务功能来划分的,所以单一原则更加偏向业务;而接口隔离更多是为了“高内聚”,偏向架构的设计。


三. 接口隔离原则的优点


接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下 5 个优点。


  1. 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
  2. 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
  3. 如果接口的粒度大小定义合理,能够保证系统的稳定性;然而,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。
  4. 使用多个专门的接口能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
  5. 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。


四. 接口隔离原则的实现方法



在具体应用接口隔离原则时,应该根据以下几个规则来衡量。


1)接口要尽量小

不能出现Fat Interface;但是要有限度,首先不能违反单一职责原则(不能一个接口对应半个职责)。

2)接口要高内聚

在接口中尽量少公布public方法。

接口是对外的承诺,承诺越少对系统的开发越有利。

3)定制服务

只提供访问者需要的方法。例如,为管理员提供IComplexSearcher接口,为公网提供ISimpleSearcher接口。

4)接口的设计是有限度的

了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同, 需要深入了解业务逻辑。


五. 接口隔离原则的建议



  1. 一个接口只服务于一个子模块或业务逻辑;
  2. 通过业务逻辑压缩接口中的public方法;
  3. 已被污染了的接口,尽量去修改;若变更的风险较大,则采用适配器模式转化处理;
  4. 拒绝盲从


五. 案例分析



下面以学生成绩管理为例来说明接口隔离原则:

分析:学生成绩管理程序一般包含查询成绩、新增成绩、删除成绩、修改成绩、计算总分、计算平均分、打印成绩信息等功能,通常我们会怎么做呢?


一: 最初的设计


通常我们设计接口的方式如下:

public interface IStudentScore {
    // 查询成绩
    public void queryScore();
    // 修改成绩
    public void updateScore();
    // 添加成绩
    public void saveScore();
    // 删除成绩
    public void delete();
    // 计算总分
    public double sum();
    // 计算平均分
    public double avg();
    // 打印成绩单
    public void printScore();
}

我们会吧所有的功能都放在一个接口里面. 这会产生什么样的问题呢?


首先, 接口的方法很多, 不利于扩展. 比如: 学生只有查看成绩,打印成绩单的权限, 没有增删改的权限; 老师拥有所有的权限.


查询成绩单:

package com.lxl.www.designPatterns.sixPrinciple.interfaceSegregationPrinciple.score;
public class QueryScore implements IStudentScore{
    @Override
    public void queryScore() {
        // 查询成绩
    }
    @Override
    public void updateScore() {
         // 没有权限
    }
    @Override
    public void saveScore() {
        // 没有权限
    }
    @Override
    public void delete() {
        // 没有权限
    }
    @Override
    public double sum() {
        // 没有权限
        return 0;
    }
    @Override
    public double avg() {
        // 没有权限
        return 0;
    }
    @Override
    public void printScore() {
        //打印成绩单
    }
}

操作成绩单

package com.lxl.www.designPatterns.sixPrinciple.interfaceSegregationPrinciple.score;
public class Operate implements IStudentScore{
    @Override
    public void queryScore() {
    }
    @Override
    public void updateScore() {
    }
    @Override
    public void saveScore() {
    }
    @Override
    public void delete() {
    }
    @Override
    public double sum() {
        return 0;
    }
    @Override
    public double avg() {
        return 0;
    }
    @Override
    public void printScore() {
    }
}

可以看出问题. 查询成绩单, 我们只会用到两个方法, 可是因为实现了接口, 不得不重写所有的方法.


如果这时候增加需求--发送给家长, 只有老师才有这个权限, 学生没有这个权限. 可是, 在接口中增加一个抽象方法以后, 所有的实现类都要重写这个方法. 这就违背了开闭原则.


2. 使用接口隔离原则的设计


采用接口隔离原则设计的接口, UML图如下:


public interface IQueryScore {
    // 查询成绩
    public void queryScore();
    // 打印成绩单
    public void printScore();
}
public interface IOperateScore {
    // 修改成绩
    public void updateScore();
    // 添加成绩
    public void saveScore();
    // 删除成绩
    public void delete();
    // 计算总分
    public double sum();
    // 计算平均分
    public double avg();
}
public class StudentOperate implements IQueryScore{
    @Override
    public void queryScore() {
        // 查询成绩
    }
    @Override
    public void printScore() {
        //打印成绩单
    }
}
public class TeacherOperate implements IQueryScore, IOperateScore{
    @Override
    public void queryScore() {
    }
    @Override
    public void updateScore() {
    }
    @Override
    public void saveScore() {
    }
    @Override
    public void delete() {
    }
    @Override
    public double sum() {
        return 0;
    }
    @Override
    public double avg() {
        return 0;
    }
    @Override
    public void printScore() {
    }
}

我们将原来的一个接口进行了接口拆分. 分为查询接口和操作接口. 这样学生端就不需要重写和他不相关的接口了.


如果将这些功能全部放到一个接口中显然不太合理,正确的做法是将它们分别放在输入模块、统计模块和打印模块等 3 个模块中,其类图如图 1 所示

相关文章
|
3月前
|
设计模式
设计模式七大原则
这篇文章介绍了设计模式中的七大原则,特别强调了单一职责原则,即一个类应该只有一个引起其行为变化的原因,以确保类功能的高内聚和低耦合。
|
3月前
|
设计模式 存储 前端开发
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
|
2月前
|
设计模式 Java 关系型数据库
设计模式——设计模式简介和七大原则
设计模式的目的和核心原则、单一职责原则、接口隔离原则、依赖倒转原则、里氏替换原则、开闭原则、迪米特法则、合成复用原则
设计模式——设计模式简介和七大原则
|
3月前
|
设计模式 算法 开发者
设计模式问题之最小知识原则(迪米特法则)对代码设计有何影响,如何解决
设计模式问题之最小知识原则(迪米特法则)对代码设计有何影响,如何解决
|
3月前
|
设计模式 前端开发 JavaScript
React开发设计模式及原则概念问题之什么是HOC(Higher-order component),HOC遵循的设计原则都有哪些
React开发设计模式及原则概念问题之什么是HOC(Higher-order component),HOC遵循的设计原则都有哪些
|
3月前
|
设计模式 前端开发 JavaScript
React开发设计模式及原则概念问题之什么是设计模式,单一职责原则如何理解
React开发设计模式及原则概念问题之什么是设计模式,单一职责原则如何理解
|
5月前
|
设计模式 uml
设计模式学习心得之前置知识 UML图看法与六大原则(下)
设计模式学习心得之前置知识 UML图看法与六大原则(下)
40 2
|
5月前
|
设计模式 Java 数据库
深入理解设计模式六大原则
深入理解设计模式六大原则
|
18天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。