第5章 接口隔离原则(ISP)

本文深入讲解了接口隔离原则(ISP)的基本概念与应用实践,包括ISP的定义、ISP与单一职责原则的区别、遵循ISP的注意事项及最佳实践。通过具体代码示例展示了如何将一个被污染的接口重构为更细粒度的接口。

一、定义

1、接口:分为两种

(1)、实例接口:Java中声明一个类,然后用new关键字产生一个实例,是对一个类型事物的描述,这是一种接口。

   例如:定义Person类,然后使用Person zhangsan = new Person()产生实例,Person类就是zhangsan的接口。

(2)、类接口:使用interface关键字定义的接口。

2、定义

(1)、使用多个专门的接口,而不使用单一的总接口,即客户端不依赖那些不需要的接口,需要对接口进行细化,保

其纯洁性。类间的依赖关系应该建立在最小的接口上

(2)、接口尽量细化,同时接口中的方法尽量少。每个接口只包含一个客户端(子模块或业务逻辑类)所需的方法即

可,这种机制称为"定制服务",即为不同的客户端提供宽窄不同的接口。

(3)、为接口定义不必要的方法,这叫"接口污染"。对于实现类来说,就是一种污染,实现类被迫实现这些不必要的

能方法。并且接口发生改变的时候不得不跟着改变。

接口设计过于臃肿,封装过度。把一个比较臃肿的接口拆分成两个专门的接口,灵活性提高,可维护性增加。接口

原则把一个臃肿的接口变为两个独立的接口,使得系统更加灵活。接口是我们对外提供的契约,通过分散定义多个

口,可以预防未来变更的扩散,提高系统的灵活性和可维护性

二、接口隔离原则和单一指责原则的区别

1、单一指责注意的是职责,从业务逻辑上进行划分的。而接口隔离要求接口尽量少(类间依赖关系最小接

口)多接口+接口方法单一  单继承+多接口==多继承。 如有一个向外提供查询服务的,但提供的接口很多,有普通

权限和高级权限的查询方法。按照单一指责的原则是允许的,只提供单一指责,即查询。但按照接口原则是不允许

的。应该按照权限提供专门的接口给不同的客户端。

2、接口隔离原则讲的就是同一个角色提供宽窄不同的接口,以应付不同的客户端。

三、使用接口隔离原则注意事项

1、接口尽量小(多个接口,灵活应对),但要有限度。对接口细化可以提高设计灵活性,但如果过小,会造成接口数

量过多,使设计复杂化。

2、为依赖接口的类定制服务,只暴漏给调用它的类所需要的方法,不需要的则隐藏起来。

3、提高内聚,减少对外交互。使接口使用最小的方法完成最多的事情。具体要求:接口中尽量少提供public方法

接口隔离的例子:很好的一个例子,好好体会接口隔离

1、Manager类代表的是管理工人的管理者

2、有两类工人,普通和高效的,都需要吃饭和工作

3、如果出现一个机器人(Robot),保持现有的设计,让Robot实现IWork接口,就会被迫实现吃饭的功能,这种情况认

为IWorker是被污染的接口。需要进行重构,细化出3个接口,一个吃饭接口(IFeedable)、IWorkable(工作)、

IRchargeable(充电)。

加入Robot类之后,一个被污染的接口设计

   

重构后符合接口隔离的原则:


这样子设计感觉很美妙,多个接口。单继承+多接口 = 多继承

#include <iostream>
//细化接口
using namespace std;

//IWorkable接口:工作 公共接口
class IWorkable
{
public:
	virtual void work() = 0;
};

//IFeedable接口:吃饭
class IFeedable
{
public:
	virtual void eat() = 0;
};

//IRechargeable接口:充电
class IRecharge
{
public:
	virtual void recharge() = 0;
};
//普通工人
class CommonWorker : public IFeedable, public IWorkable
{
public:
	void eat() { cout << "common worker eat()..." << endl; }
	void work() { cout << "common worker work()..." << endl; }
};
//高效工人
class EfficentWorker : public IFeedable, public IWorkable
{
public:
	void eat() { cout << "Efficent worker eat()..." << endl; }
	void work() { cout << "Efficent worker work()..." << endl; }
};
//机器人
class Robot : public IWorkable, public IRecharge
{
public:
	void work() { cout << "Robot work()..." << endl; }
	void recharge() { cout << "Robot recharge()..." << endl; }
};
//管理类
class Manager
{
	//依赖实现的三种方式:构造函数  setter方法  接口注入(java常用)
private:
	IWorkable* worker;
public:
	void setWorker(IWorkable* w) { worker = w; }
	void mange()
	{
		worker->work();
	}
};

int main()
{
	CommonWorker cmw;
	EfficentWorker efw;
	Robot rb;

	Manager mn;

	//管理员让普通工人工作
	mn.setWorker(&cmw);
	mn.mange();

	//管理员让高效工人工作
	mn.setWorker(&efw);
	mn.mange();

	//管理员让机器人工作
	mn.setWorker(&rb);
	mn.mange();

	cin.get();
	return 0;
}


四、最佳实践

1、一个接口只服务于一个子模块或业务逻辑

2、通过业务逻辑压缩接口中的public方法,以提高内聚

3、已经被污染的接口尽量修改,若变更的风险大,则采用适配器模式进行转化处理

4、深入了解业务逻辑,最好的接口设计就在你的手中!实践  经验 领悟!

根据经验和常识决定接口的粒度大小,接口粒度太小,导致接口数据剧增,开发人员呛死在接口的海洋;

接口粒度太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。                                                                                                                                                                                        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值