设计模式 之 接口隔离原则 (Interface Segregation Principle)

Motivation

动机

When we design an application we should take care how we are going to make abstract a module which contains several submodules. Considering the module implemented by a class, we can have an abstraction of the system done in an interface. But if we want to extend our application adding another module that contains only some of the submodules of the original system, we are forced to implement the full interface and to write some dummy methods. Such an interface is named fat interface or polluted interface. Having an interface pollution is not a good solution and might induce inappropriate behavior in the system.

当设计应用时,我们应该细心考虑如何抽象一个模块,其内部包含多个子模块。假定模块用类实现,我们可以使用接口来完成一个系统的抽象。但是如果想使用另外一个包含原有系统中部分子模块的新模块扩展应用时,我们不得不实现全部接口,并且写一些无用的假方法。这样的接口被称为胖接口或者污染的接口。含有接口污染并不好,所以需要缩减系统中不合适的行为。

The Interface Segregation Principle states that clients should not be forced to implement interfaces they don't use. Instead of one fat interface many small interfaces are preferred based on groups of methods, each one serving one submodule.

接口隔离原则要求客户端不应该强制实现它们不使用的接口。相比胖接口,应该优先使用包含多组方法小接口,每个接口为一个子模块服务。

Intent

目的

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

客户端不应该被强制依赖它们不使用的接口。

Example

Below is an example which violates the Interface Segregation Principle. We have a Manager class which represent the person which manages the workers. And we have 2 types of workers some average and some very efficient workers. Both types of workers works and they need a daily launch break to eat. But now some robots came in the company they work as well , but they don't eat so they don't need a launch break. One on side the new Robot class need to implement the IWorker interface because robots works. On the other side, the don't have to implement it because they don't eat.

下面是一个违反接口隔离原则的例子。Manager类表示用来管理workers的人员,我们拥有2种worker类型,一些是一般的和一些效率高的。2种worker都需要工作,并且需要日常午休来吃东西。但是现在机器人Robot进入到了公司,它们同样工作,但是它们不吃东西,所以也不需要午休。一方面Robot要工作,所以需要实现IWorker接口,另外一方面,Robot不吃东西,所以不需要实现IWorker接口。

This is why in this case the IWorker is considered a polluted interface.

这就是为什么IWorker被认为是被污染的接口。

If we keep the present design, the new Robot class is forced to implement the eat method. We can write a dummy class which does nothing(let's say a launch break of 1 second daily), and can have undesired effects in the application(For example the reports seen by managers will report more lunches taken than the number of people).

如果保持现有设计,新的Robot类需要强制实现eat方法。我们需要实现一个假的类,它的eat方法什么也不做(假定日常午休1秒钟),这样可能会在应用中得到不期望的结果(比如,Manager看到的报告中会显示比实际worker数量要多的午休次数)。

According to the Interface Segregation Principle, a flexible design will not have polluted interfaces. In our case the IWorker interface should be split in 2 different interfaces.

遵循接口隔离原则,灵活的设计不会包含污染的接口。在本例中,IWorker接口应该被拆分成2个不同的接口。

 1 // interface segregation principle - bad example
 2 interface IWorker {
 3     public void work();
 4     public void eat();
 5 }
 6 
 7 class Worker implements IWorker{
 8     public void work() {
 9         // ....working
10     }
11     public void eat() {
12         // ...... eating in launch break
13     }
14 }
15 
16 class SuperWorker implements IWorker{
17     public void work() {
18         //.... working much more
19     }
20 
21     public void eat() {
22         //.... eating in launch break
23     }
24 }
25 
26 class Manager {
27     IWorker worker;
28 
29     public void setWorker(IWorker w) {
30         worker=w;
31     }
32 
33     public void manage() {
34         worker.work();
35     }
36 }

 

Following it's the code supporting the Interface Segregation Principle. By splitting the IWorker interface in 2 different interfaces the new Robot class is no longer forced to implement the eat method. Also if we need another functionality for the robot like recharging we create another interface IRechargeble with a method recharge.

下面是支持接口隔离原则的代码。将IWorker接口拆分成2个不同的接口,Robot类不需要再强制实现eat方法了。同样的,如果我们需要一个新功能比如给机器人修整,我们需要创建一个新的接口IRechargeable,内部包含一个recharge方法。

 1 // interface segregation principle - good example
 2 interface IWorker extends Feedable, Workable {
 3 }
 4 
 5 interface IWorkable {
 6     public void work();
 7 }
 8 
 9 interface IFeedable{
10     public void eat();
11 }
12 
13 class Worker implements IWorkable, IFeedable{
14     public void work() {
15         // ....working
16     }
17 
18     public void eat() {
19         //.... eating in launch break
20     }
21 }
22 
23 class Robot implements IWorkable{
24     public void work() {
25         // ....working
26     }
27 }
28 
29 class SuperWorker implements IWorkable, IFeedable{
30     public void work() {
31         //.... working much more
32     }
33 
34     public void eat() {
35         //.... eating in launch break
36     }
37 }
38 
39 class Manager {
40     Workable worker;
41 
42     public void setWorker(Workable w) {
43         worker=w;
44     }
45 
46     public void manage() {
47         worker.work();
48     }
49 }

 

Conclusion

结论

If the design is already done fat interfaces can be segregated using the Adapter pattern.

如果接口已经被实现为胖接口,那么可以使用适配器模式对其进行拆分。

Like every principle Interface Segregation Principle is one principle which require additional time and effort spent to apply it during the design time and increase the complexity of code. But it produce a flexible design. If we are going to apply it more than is necessary it will result a code containing a lot of interfaces with single methods, so applying should be done based on experience and common sense in identifying the areas where extension of code are more likely to happens in the future.

像每个规则一样,接口隔离原则是也需要在设计接口时花费更多的时间和精力,并且会增加代码复杂度。但是遵循此规则会使设计更加灵活。如果我们在不是必须的情况下使用它,将会使代码中包含很多单个方法的接口,所以使用该原则需要建立在经验和常识的基础上,以辨别代码的扩展中哪些部分在未来使可能发生变化。

 

原文地址:https://www.oodesign.com/interface-segregation-principle.html

posted @ 2020-04-12 16:53  AlexAlex  阅读(531)  评论(0编辑  收藏  举报