七、设计模式的六大设计原则之接口隔离原则(ISP, Interface Segregation Principle)

1. 何为接口隔离原则

定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。

定义解读:

该定义包含以下三层含义:

a. 一个类对另一个类的依赖应该建立在最小的接口上;
b. 一个接口代表一个角色,不应该将不同的角色都交给一个接口,因为这样可能会形成一个臃肿的大接口;
b. 不应该强迫客户端依赖他们从来不用的方法。

接口隔离原则有点像单一职责原则,但是也有区别,在单一职责原则中,一个接口可能有多个方法,提供给多种不同的调用者所调用,但是它们始终完成同一种功能,因此它们符合单一职责原则,却不符合接口隔离原则,因为这个接口存在着多种角色,因此可以拆分成更多的子接口,以供不同的调用者所调用。比如说,项目中我们通常有一个Web服务管理的类,接口定义中,我们可能会将所有模块的数据调用方法都在接口中进行定义,因为它们都完成的是同一种功能:和服务器进行数据交互;但是对于具体的业务功能模块来说,其他模块的数据调用方法它们从来不会使用,因此不符合接口隔离原则。

优点

使用接口隔离原则,意在设计一个短而小的接口和类,符合我们常说的高内聚低耦合的设计思想,从而使得类具有很好的可读性、可扩展性和可维护性。

2. 情景设置

类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类C来说不是最小接口,而类B和类D必须去实现它们不需要的方法。下面通过一个UML图来说明这种现象,如图2-1所示:

图2-1

在这里,我们定义了一个动物活动的接口IAnimal,里面有4个方法:飞行fly、行走walk、吃eat和工作work,然后分别用人类People和鸟类Bird实现了这个接口。中国人类ChinesePeople和鹦鹉类Parrot通过接口IAnimal分别依赖类People和类Bird。很明显,对于ChinesePeople来说,fly方法是多余的,因为人不会飞;对于Parrot类来说,work方法是多余的,因为鹦鹉不需要工作。接口IAnimal对于类ChinesePeople和类Parrot来说不是最小接口。

解决方案

将臃肿的接口IAnimal拆分为独立的几个接口,类ChinesePeople和类Parrot分别与它们需要的接口建立依赖关系,也就是采用接口隔离原则。修改后的UML图如图2-2所示:

图2-2

3. 代码实现

(1)三个接口

@protocol IAnimal <NSObject>

//- (void)work;  // 使用接口隔离原则,将该方法放到其他接口
//- (void)fly;  // 使用接口隔离原则,将该方法放到其他接口
@optional
- (void)walk;
@required
- (void)eat;

@end


@protocol IPeople <NSObject>

- (void)work;

@end


@protocol IBird <NSObject>

- (void)fly;

@end

(2)People

@interface People : NSObject<IAnimal,IPeople>

@end


@implementation People

- (void)work
{
    NSLog(@"I am working");
}

//- (void)fly
//{
//    NSLog(@"I am flying");
//}

- (void)walk
{
    NSLog(@"I am walking");
}

- (void)eat
{
    NSLog(@"I am eating");
}

@end

(3)Bird

@interface Bird : NSObject<IAnimal,IBird>

@end


@implementation Bird

//- (void)work
//{
//    NSLog(@"I am working");
//}

- (void)fly
{
    NSLog(@"I am flying");
}

- (void)walk
{
    NSLog(@"I am walking");
}

- (void)eat
{
    NSLog(@"I am eating");
}

@end

(4)ChinesePeople

@interface ChinesePeople : NSObject

@property (nonatomic,assign) id<IAnimal> animalDelegate;
@property (nonatomic,assign) id<IPeople> peopleDelegate;

@end


@implementation ChinesePeople
@synthesize animalDelegate = _animalDelegate;
@synthesize peopleDelegate = _peopleDelegate;

- (void)work
{
//    [_animalDelegate work];
    [_peopleDelegate work];
}

//- (void)fly
//{
//    [_animalDelegate fly];
//}

- (void)walk
{
    [_animalDelegate walk];
}

- (void)eat
{
    [_animalDelegate eat];
}

@end

(5)Parrot

@interface Parrot : NSObject

@property (nonatomic,assign) id<IAnimal> animalDelegate;
@property (nonatomic,assign) id<IBird> birdDelegate;

@end


@implementation Parrot
@synthesize animalDelegate = _animalDelegate;
@synthesize birdDelegate = _birdDelegate;

//- (void)work
//{
//    [_animalDelegate work];
//}

- (void)fly
{
//    [_animalDelegate fly];
    [_birdDelegate fly];
}

- (void)walk
{
    [_animalDelegate walk];
}

- (void)eat
{
    [_animalDelegate eat];
}

@end

(6)客户端调用

ChinesePeople *chinesePeople = [[ChinesePeople alloc] init];
People *people = [[People alloc] init];
        
chinesePeople.animalDelegate = people;
chinesePeople.peopleDelegate = people;
        
[chinesePeople work];
[chinesePeople eat];
[chinesePeople walk];

从UML图可以看到,遵守接口隔离原则,会使代码量增加不少,源码中也是这样;实际上,iOS在定义协议的时候,可以设置方法为可选实现(@optional)和必须实现(@required,默认值),我们可以设置work方法和fly方法为可选实现的方法,这样在类People和类Bird中,这两个方法可以根据需要来决定是否实现。采用这种方式,功能上实现是没有问题,对于简单的接口来说,也便于维护和管理。但是,当方法随着业务需求的增加而不断增加的话,如果我们不应用接口隔离原则,那么就可能形成一个庞大臃肿的接口,这样的接口的可维护性和重用性是很差的。因此,我们应该尽量细化接口,本篇将一个接口变更为3个专用的接口所采用的就是接口隔离原则。在项目开发中,依赖几个专用的接口要比依赖一个综合的接口更加灵活。通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

虽然接口隔离原则很有意义,但在实际项目中,应该注意度的把握,接口设计的过大或过小都不好,应该根据实际情况多思考再进行设计。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转载标注声明:http://www.uml.org.cn/sjms/201211023.asp 目录:[设计模式六...
    Bloo_m阅读 740评论 0 7
  • 设计模式六大原则 设计模式六大原则(1):单一职责原则 定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类...
    viva158阅读 786评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,026评论 19 139
  • 设计模式六大原则 单一职责原则 实现类要职责单一 里氏替换原则 不要破坏继承体系 依赖倒置原则 要面向接口编...
    蛍火之恋阅读 475评论 0 1
  • 阴雨天的温暖不就是,一杯冒着热气的奶茶或咖啡,和屏幕那端的回应。 遇见一个很好的人,感觉就像是得到了上天的眷顾。 ...
    yt豆爷阅读 253评论 0 0