设计模式原则之开闭原则

定义

Software entities like classes,modules and functions should be open for extension but closed for modifications.

一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。


概念理解

开闭原则明确的告诉我们:软件实现应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化的。

那什么是软件实体呢?

1.项目或软件产品中按照一定的逻辑规则划分的模块

2.抽象和类

3.方法

一个软件产品只要在生命周期内,都会发生变化,即然变化是一个事实,我们就应该在设计时尽量适应这些变化,以提高项目的稳定性和灵活性,真正实现“拥抱变化”。开闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改现有代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。


模拟场景

假设你是一个书店老板,你平时正常销售书籍


场景代码

@protocol Book<NSObject>

-(NSString *)getName;

-(float)getPrice;

-(NSString *)getAuthor;

@end

#import "Book.h"

@interface BookObject : NSObject<Book>

- (instancetype)initWithName:(NSString *)name price:(float)price author:(NSString *)author NS_DESIGNATED_INITIALIZER;

@end

#import "BookObject.h"

@interface BookObject()

@property (nonatomic,strong) NSString * name;

@property (nonatomic,strong) NSString * author;

@property (nonatomic,assign) float price;

@end

@implementation BookObject

-(instancetype)initWithName:(NSString *)name price:(float)price author:(NSString *)author{

    if (self = [super init]) {

        self.name = name;

        self.price = price;

        self.author = author;

    }

    return self;

}

-(NSString *)getName{

    return self.name;

}

-(float)getPrice{

    return self.price;

}

-(NSString *)getAuthor{

    return self.author;

}

-(NSString *)description{

    NSLog(@"书的名字 %@,当前买卖价格:%f,书的作者%@",[self getName],[self getPrice],[self getAuthor]);

    return nil;

}

@end

测试

///正常卖书

id<Book> book = [[BookObject alloc]initWithName:@"《笑傲江湖》" price:50 author:@"金庸"];

    [book description];

结果

2018-04-03 14:14:17.995418+0800 设计模式原则[26260:5566097] 书的名字 《笑傲江湖》,当前买卖价格:50.000000,书的作者金庸


场景变更

项目投入使用的时候,每逢节假日要对商品进行打折销售。如何应该这样的变化呢?

方案一

修改接口

在Book协议中增加一个-getOffPrice 方法,专门处理打折。但是所有的实现该协议的BookObject中都要修改,并且Book协议应该稳定并且可靠,不应该经常发生变化,否则就失去了接口的契约作用。因此放弃

方案二

修改实现类

直接修改BookObject 对象的-getPrice 方法。这个 方法一看就有问题,这样就没有办法处理不打折商品了。方案不好

方案三

通过扩展实现变化

我们可以通过增加一个子类BookDiscountObject,覆盖-getPrice 方法。这种方法对现有的代码没有影响,风险小,是个好办法。


开闭原则UML图

开闭原则UML图

场景变更新增代码

#import "BookObject.h"

@interface BookDiscountObject : BookObject

@end

#import "BookDiscountObject.h"

@implementation BookDiscountObject

-(float)getPrice{

    float price =[super getPrice];

    if (price>40) {

        price = 0.8*40;

    }

    return price;

}

@end

测试代码

///正常卖书 id<Book> book = [[BookObject alloc]initWithName:@"《笑傲江湖》" price:50 author:@"金庸"];

    [book description];

    ///打折销售

    book = [[BookDiscountObject alloc]initWithName:@"《笑傲江湖》" price:50 author:@"金庸"];

    [book description];

结果

2018-04-03 14:14:17.995418+0800 设计模式原则[26260:5566097] 书的名字 《笑傲江湖》,当前买卖价格:50.000000,书的作者金庸

2018-04-03 14:14:17.995599+0800 设计模式原则[26260:5566097] 书的名字 《笑傲江湖》,当前买卖价格:32.000000,书的作者金庸


变化分类

逻辑变化 

只变化了一个逻辑,而不涉及其他模块,比如一个算法是a*b*c,现在需要修改为a+b+c,可以直接通过修改原有类中的方法的方式来完成,前提条件是所有依赖或关联类都按照相同的逻辑处理

子模块变化 

一个模块变化,会对其它的模块产生影响,特别是一个低层次的模块变化必然引起高层模块的变化,因此在通过扩展完成变化


使用开闭原则的理由

第一:开闭原则非常有名,只要是面向对象编程,在开发时都会强调开闭原则

第二:开闭原则是最基础的设计原则,其它的五个设计原则都是开闭原则的具体形态,也就是说其它的五个设计原则是指导设计的工具和方法,而开闭原则才是其精神领袖。依照java语言的称谓,开闭原则是抽象类,而其它的五个原则是具体的实现类。

第三:开闭原则可以提高复用性 

在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来,不是在一个类中独立实现一个业务逻辑。只有这样的代码才可以复用,粒度越小,被复用的可能性越大。那为什么要复用呢?减少代码的重复,避免相同的逻辑分散在多个角落,减少维护人员的工作量。那怎么才能提高复用率呢?缩小逻辑粒度,直到一个逻辑不可以分为止。

第四:开闭原则可以提高维护性 

一款软件量产后,维护人员的工作不仅仅对数据进行维护,还可能要对程序进行扩展,维护人员最乐意的事是扩展一个类,而不是修改一个类。让维护人员读懂原有代码,再进行修改,是一件非常痛苦的事情,不要让他在原有的代码海洋中游荡后再修改,那是对维护人员的折磨和摧残。

第五:面向对象开发的要求 

万物皆对象,我们要把所有的事物抽象成对象,然后针对对象进行操作,但是万物皆发展变化,有变化就要有策略去应对,怎么快速应对呢?这就需要在设计之初考虑到所有可能变化的因素,然后留下接口,等待“可能”转变为“现实”。


开闭原则是使用

第一:抽象约束 

抽象是对一组事物的通用描述,没有具体的实现,也就表示它可以有非常多的可能性,可以跟随需求的变化而变化。因此,通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:

通过接口或抽象类约束扩散,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法。

参数类型,引用对象尽量使用接口或抽象类,而不是实现类,这主要是实现里氏替换原则的一个要求

抽象层尽量保持稳定,一旦确定就不要修改

第二:元数据(metadata)控件模块行为 

编程是一个很苦很累的活,那怎么才能减轻压力呢?答案是尽量使用元数据来控制程序的行为,减少重复开发。什么是元数据?用来描述环境和数据的数据,通俗的说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

第三:制定项目章程 

在一个团队中,建立项目章程是非常重要的,因为章程是所有人员都必须遵守的约定,对项目来说,约定优于配置。这比通过接口或抽象类进行约束效率更高,而扩展性一点也没有减少。

第四:封装变化 

对变化封装包含两层含义: 

(1)将相同的变化封装到一个接口或抽象类中 

(2)将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。 

封装变化,也就是受保护的变化,找出预计有变化或不稳定的点,我们为这些变化点创建稳定的接口。

参考博客

六大设计原则之开闭原则

源代码地址

下一篇博客讲解

设计模式原则之里氏替换原则

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • 设计模式六大原则 设计模式六大原则(1):单一职责原则 定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类...
    viva158阅读 763评论 0 1
  • 目录: 设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒...
    加油小杜阅读 716评论 0 1
  • 转载标注声明:http://www.uml.org.cn/sjms/201211023.asp 目录:[设计模式六...
    Bloo_m阅读 699评论 0 7
  • 设计模式6大原则 转自:http://www.cnblogs.com/devinzhang/archive/201...
    犀利的小眼神阅读 426评论 0 1
  • 【连载】《阡陌》目录 【连载】《阡陌》(十二) 十七 当焦仲卿下了差回家,直奔厢房看妻子的时候,只见妻子直挺挺的躺...
    于昰阅读 269评论 0 1