PHP面向对象五大原则之接口隔离原则(ISP)详解


Posted in PHP onApril 04, 2018

本文实例讲述了PHP面向对象五大原则之接口隔离原则(ISP)。分享给大家供大家参考,具体如下:

设计应用程序的时候,如果一个模块包含多个子模块,那么我们应该小心对模块做出抽象。设想该模块由一个类实现,我们可以把系统抽象成一个接口。但是要添加一个新的模块扩展程序时,如果要添加的模块只包含原系统中的一些子模块,那么系统就会强迫我们实现接口中的所有方法,并且清寒要编写一些哑方法。这样的接口被称为肚胖接口或者被污染的接口,使用这样的接口将会给系统引入一些不当的行为,这些不当的行为可能导致不正确的结果,也可能导入资源浪费。

1.接口隔离

接口隔离原则(Interface Segregation Principle, ISP)表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口替代它,每个接口服务于一个子模块。简单地说,就是使用多个专门的接口比使用单个接口要好很多。

ISP的主要观点如下:

1)一个类对另外一个类的依赖性应当是建立在最小的接口上的。

ISP可以达到不强迫客户(接口的使用方法)依赖于他们不用的方法,接口的实现类应该只呈现为单一职责的角色(遵循SRP原则)

ISP还可以降低客户之间的相互影响---当某个客户要求提供新的职责(需要变化)而迫使接口发生改变时,影响到其他客户程序的可能性最小。

2)客户端程序不应该依赖它不需要的接口方法(功能)。

客户端程序就应该依赖于它不需要的接口方法(功能),那依赖于什么?依赖它所需要的接口。客户端需要什么接口就是提供什么接口,把不需要的接口剔除,这就要求对接口进行细化,保证其纯洁性。

比如在继承时,由于子类将继承父类中的所有可用方法;而父类中的某些方法,在子类中可能并不需要。例如,普通员工和经理都继承自雇员这个接口,员工需要每天写工作日志,而经理不需要。因此不能用工作日志来卡经理,也就是经理不应该依赖于提交工作日志这个方法。

可以看出,ISP和SRP在概念上是有一定交叉的。事实上,很多设计模式在概念上都有交叉,甚至你很难判断一段代码属于哪一种设计模式。

ISP强调的是接口对客户端的承诺越少越好,并且要做到专一。当某个客户程序的要求发生变化,而迫使接口发生改变时,影响到其他客户程序的可能性小。这实际上就是接口污染的问题。

2.对接口的污染

过于臃肿的接口设计是对接口的污染。所谓的接口污染就是为接口添加不必要的职责,如果开发人员在接口中增加一个新功能的目的只是减少接口实现类的数目,则此设计将导致接口被不断地“污染”并“变胖”。

“接口隔离”其实就是定制化服务设计的原则。使用接口的多重继承实现对不同的接口的组合,从而对外提供组合功能---达到“按需提供服务”。

接口即要拆,但也不能拆得太细,这就得有个标准,这就是高内聚。接口应该具备一些基本的功能,能独一完成一个基本的任务。

在实际应用中,会遇到如下问题:比如,我需要一个能适配多种类型数据库的DAO实现,那么首先应实现一个数据库操作的接口,其中规定一些数据库操作的基本方法,比如连接数据库、增删改查、关闭数据库等。这是一个最少功能的接口。对于一些MySQL中特有的而其他数据库里并不存在的或性质不同的方法,如PHP里可能用到的MySQL的pconnect方法,其他数据库里并不存在和这个方法相同的概念,这个方法也就不应该出现在这个基本的接口里,那这个基本的接口应该有哪些基本的方法呢?PDO已经告诉你了。

PDO是一个抽象的数据库接口层,它告诉我们一个基本的数据库操作接口应该实现哪些基本的方法。接口是一个高层次的抽象,所以接口里的方法都应该是通用的、基本的、不易变化的。

还有一个问题,那些特有的方法应该怎么实现?根据ISP原则,这些方法可以在别一个接口中存在,让这个“异类”同时实现这两个接口。

对于接口的污染,可以考虑这两条处理方式:

利用委托分离接口。

利用多继承分离接口。

委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理,如策略模式、代理模式等中都应用到了委托的概念。

再来看一下实例说明

你是否遇到过非常“胖”的接口呢?

举个例子来说吧:有一个跟动物有关的接口,代码如下:

<?php
interface Animal{
  public function walk();
  public function speak();
}

狗是这个接口的一个具体实现:

<?php
require_once "animal.php";
class Dog implements Animal{
  public function walk(){
    echo "dogs can walk";
  }
  public function speak(){
    echo "dogs can speak";
  }
}

ok,现在我们想创建一个鱼类,它会游泳,怎么办呢?我们必须要修改接口,还会影响到dog类的实现,而fish也需要实现walk和speak方法,如下代码所示:

Animal接口类:

<?php
interface Animal{
  public function walk();
  public function speak();
  public function swim();
}

dog类:

<?php
require_once "animal.php";
class Dog implements Animal{
  public function walk(){
    echo "dogs can walk";
  }
  public function speak(){
    echo "dogs can speak";
  }
  public function swim(){
  }
}

fish类:

<?php
require_once "animal.php";
class Fish implements Animal{
  public function walk(){
  }
  public function speak(){
  }
  public function swim(){
    echo "fish can swim";
  }
}

这时Animal接口类就呈现出了”胖“接口的特征了。所谓胖接口其实就是接口中定义了不是所有实现类都需要的方法,就像Animal接口类,有些动物是不会游泳的,有些动物是不会行走的,还有些动物是不会飞的。如果将这些方法都写在一个Animal接口类中,那么后期的扩展和维护简直就是一场灾难。

那么,怎么解决以上问题呢?

很简单,接口细化即可,将Animal接口类拆分成三个接口类:

animalCanWalk接口类:

<?php
interface animalCanSpeak{
  public function speak();
}

AnimalCanSwim接口类:

<?php
interface AnimalCanSwim{
  public function swim();
}

animalCanSpeak接口类:

<?php
interface animalCanSpeak{
  public function speak();
}

定义好这几个接口类之后,dog和fish的实现就容易多了,

<?php
require_once "animalCanSpeak.php";
require_once "animalCanWalk.php";
class Dog implements animalCanSpeak,animalCanWalk{
  public function walk(){
    echo "dogs can walk";
  }
  public function speak(){
    echo "dogs can speak";
  }
}
<?php
require_once "animalCanSwim.php";
class Fish implements AnimalCanSwim{
  public function swim(){
    echo "fish can swim";
  }
}

总结一下:

接口隔离原则(Interface  Segregation Principle, ISP)的概念:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php一些公用函数的集合
Mar 27 PHP
PHP 第三节 变量介绍
Apr 28 PHP
基于php设计模式中工厂模式详细介绍
May 15 PHP
php判断字符串在另一个字符串位置的方法
Feb 27 PHP
CodeIgniter安全相关设置汇总
Jul 03 PHP
php实现把url转换迅雷thunder资源下载地址的方法
Nov 07 PHP
php从数组中随机选择若干不重复元素的方法
Mar 14 PHP
php压缩和解压缩字符串的方法
Mar 14 PHP
求帮忙修改个php curl模拟post请求内容后并下载文件的解决思路
Sep 20 PHP
Laravel使用Caching缓存数据减轻数据库查询压力的方法
Mar 15 PHP
php实现的三个常用加密解密功能函数示例
Nov 06 PHP
laravel获取不到session的三种解决办法【推荐】
Sep 16 PHP
PHP面向对象五大原则之开放-封闭原则(OCP)详解
Apr 04 #PHP
PHP面向对象五大原则之单一职责原则(SRP)详解
Apr 04 #PHP
PHP基于面向对象实现的留言本功能实例
Apr 04 #PHP
PHP设计模式之工厂模式定义与用法详解
Apr 03 #PHP
PHP设计模式之原型模式定义与用法详解
Apr 03 #PHP
thinkPHP框架自动填充原理与用法分析
Apr 03 #PHP
PHP设计模式之适配器模式定义与用法详解
Apr 03 #PHP
You might like
PHP安全配置
2006/12/06 PHP
PHP随机数生成代码与使用实例分析
2011/04/08 PHP
yii2整合百度编辑器umeditor及umeditor图片上传问题的解决办法
2016/04/20 PHP
Thinkphp实现站点静态化的方法详解
2017/03/21 PHP
php 字符串中是否包含指定字符串的多种方法
2018/04/12 PHP
JQuery Tips(2) 关于$()包装集你不知道的
2009/12/14 Javascript
原生javascript实现图片轮播效果代码
2010/09/03 Javascript
基于jQuery的左右滚动实现代码
2010/12/03 Javascript
js将控件隐藏的方法及display属性介绍
2013/07/04 Javascript
javascript显式类型转换实例分析
2015/04/25 Javascript
javascript新闻跑马灯实例代码
2020/07/29 Javascript
Nodejs中解决cluster模块的多进程如何共享数据问题
2016/11/10 NodeJs
JavaScript ES6中CLASS的使用详解
2016/11/22 Javascript
PHP实现本地图片上传和验证功能
2017/02/27 Javascript
Jquery属性的获取/设置及样式添加/删除操作技巧分析
2019/12/23 jQuery
JavaScript代码实现微博批量取消关注功能
2021/02/05 Javascript
Python 除法小技巧
2008/09/06 Python
python的Template使用指南
2014/09/11 Python
python实现网站的模拟登录
2016/01/04 Python
Python3爬楼梯算法示例
2019/03/04 Python
Python对接 xray 和微信实现自动告警
2019/09/17 Python
Tensorflow与Keras自适应使用显存方式
2020/06/22 Python
python接入支付宝的实例操作
2020/07/20 Python
PyQt5通过信号实现MVC的示例
2021/02/06 Python
夏威夷灵感服装及配饰:Reyn Spooner
2018/09/18 全球购物
纯净、自信、100%的羊绒服装:360Cashmere
2021/02/20 全球购物
自动化专业本科毕业生求职信
2013/10/20 职场文书
应届生求职信写作技巧
2013/10/24 职场文书
给导游的表扬信
2014/01/10 职场文书
在校生自我鉴定
2014/01/23 职场文书
会议室标语
2014/06/21 职场文书
消防安全月活动总结
2015/05/08 职场文书
2016年基层党组织公开承诺书
2016/03/25 职场文书
Python用tkinter实现自定义记事本的方法详解
2022/03/31 Python
springboot为异步任务规划自定义线程池的实现
2022/06/14 Java/Android
Nginx代理Redis哨兵主从配置的实现
2022/07/15 Servers