上一篇文章,我们讲了一个最基础的设计原则:单一职责原则。这一讲,我们来看下一个设计原则:开放封闭原则。

作为一名程序员,来了一个需求就要改一次代码,这种方式我们已经见怪不怪了,甚至已经变成了一种下意识的反应。修改也很容易,只要我们按照之前的惯例如法炮制就好了。

这是一种不费脑子的做法,却伴随着长期的伤害。每人每次都只改了一点点,但是,经过长期积累,再来一个新的需求,改动量就要很大了。而在这个过程中,每个人都很无辜,因为每个人都只是遵照惯例在修改。但结果是,所有人都受到了伤害,代码越来越难以维护。

既然“修改”会带来这么多问题,那我们可以不修改吗?开放封闭原则就提供了这样的一个新方向。

简介

开放封闭原则是这样表述的:软件实体(类、模块、函数)应该对扩展开放,对修改封闭。

这个说法是 Bertrand Meyer 在其著作《面向对象软件构造》(Object-Oriented Software Construction)中提出来的,它给软件设计提出了一个极高的要求:不修改代码。

或许你想问,不修改代码,那我怎么实现新的需求呢?答案就是靠扩展。用更通俗的话来解释,就是新需求应该用新代码实现。

开放封闭原则向我们描述的是一个结果,就是我们可以不修改代码而仅凭扩展就完成新功能。但是,这个结果的前提是要在软件内部留好扩展点,而这正是需要我们去设计的地方。因为每一个扩展点都是一个需要设计的模型

解释

举个例子,假如我们正在开发一个酒店预订系统,针对不同的用户,我们需要计算出不同的房价。比如,普通用户是全价,金卡是 8 折,银卡是 9 折,代码写出来可能是这样的:

class HotelService {public double getRoomPrice(final User user, final Room room) {double price = room.getPrice();if (user.getLevel() == Level.GOLD) {return price * 0.8;}if (user.getLevel() == Level.SILVER) {return price * 0.9;}return price;}
}

这时,新的需求来了,要增加白金卡会员,给出 75 折的优惠,如法炮制的写法应该是这样的:

class HotelService {public double getRoomPrice(final User user, final Room room) {double price = room.getPrice();if (user.getLevel() == UserLevel.GOLD) {return price * 0.8;}if (user.getLevel() == UserLevel.SILVER) {return price * 0.9;}if (user.getLevel() == UserLevel.PLATINUM) {return price * 0.75;}return price;}
}

显然,这种做法就是修改代码的做法,每增加一个新的类型就要修改一次代码。但是,一个有各种级别用户的酒店系统肯定不只是房价有区别,提供的服务也可能有区别。可想而知,每增加一个用户级别,我们要改的代码就漫山遍野。

那应该怎么办呢?我们应该考虑如何把它设计成一个可以扩展的模型。在这个例子里面,既然每次要增加的是用户级别,而且各种服务的差异都体现在用户级别上,我们就需要一个用户级别的模型。在前面的代码里,用户级别只是一个简单的枚举,我们可以给它丰富一下:

interface UserLevel {double getRoomPrice(Room room);
}class GoldUserLevel implements UserLevel {public double getRoomPrice(final Room room) {return room.getPrice() * 0.8;}
}class SilverUserLevel implements UserLevel {public double getRoomPrice(final Room room) {return room.getPrice() * 0.9;}
}

我们原来的代码就可以变成这样:

class HotelService {public double getRoomPrice(final User user, final Room room) {return user.getRoomPrice(room);}
}class User {private UserLevel level;...public double getRoomPrice(final Room room) {return level.getRoomPrice(room);}
}

这样一来,再增加白金用户,我们只要写一个新的类就好了:

class PlatinumUserLevel implements UserLevel {public double getRoomPrice(final Room room) {return room.getPrice() * 0.75;}
}

之所以我们可以这么做,是因为我们在代码里留好了扩展点:UserLevel。在这里,我们把原来的只支持枚举值的 UserLevel 升级成了一个有行为的 UserLevel。

经过这番改造,HotelService 的 getRoomPrice 这个方法就稳定了下来,我们就不需要根据用户级别不断地调整这个方法了。至此,我们就拥有了一个稳定的构造块,可以在后期的工作中把它当做一个稳定的模块来使用。

当然,在这个例子里,这个方法是比较简单的。而在实际的项目中,业务方法都会比较复杂。

总结

今天,我们讲了开放封闭原则,软件实体应该对扩展开放,对修改封闭。简单地说,就是不要修改代码,新的功能要用新的代码实现。

其实,道理大家都懂,但对很多人来说,做到是有难度的,尤其是在代码里留下扩展点,往往是需要有一定设计能力的。很多优秀的软件在设计上都给我们提供了足够的扩展能力,向这些软件的接口学习,我们可以学到更多的东西。

显然,要想提供扩展点,就需要面向接口编程。但是,是不是有了接口,就是好的设计了呢?下一讲,我们来看设计一个接口还需要满足什么样的原则。

设计模式原则之:开放封闭原则相关推荐

  1. 大话设计模式三之单一职责原则、开放-封闭原则、依赖倒置原则、里氏代换原则

    单一职责原则 单一职责原则(SRP),意思就是说,功能要单一.准确解释是,就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或 ...

  2. 设计原则之开放-封闭原则

    参考资料 曾探<JavaScript设计模式与开发实践>: <JavaScript设计模式与开发实践>原则篇(3)-- 开放-封闭原则 设计原则和编程技巧之开放-封闭原则 定义 ...

  3. 设计原则 单一职责原则、开放封闭原则、依赖倒置原则、里氏代换原则、迪米特法则

    目录 1 单一职责原则 2 开放封闭原则 3 依赖倒置原则 4 里氏代换原则 5 迪米特法则 1 单一职责原则 比如:电脑内存坏了就应该更换内存,不应该更换CPU (内存负责内存.CPU负责CPU) ...

  4. 设计模式 学习笔记(2)单一职责原则、开放封闭原则、依赖倒转原则

    (3)单一职责原则 单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因.例如,我们在写一个窗体应用程序,一般都会生成一个Form这样的类,于是我们就把各种各样的代码,像算法.数据库访问 ...

  5. 三、单一职责原则、开放-封闭原则、依赖倒转原则

    一.单一职责原则 1.定义:就一个类而言,应该仅有一个引起它变化的原因. 2.为什么要?:如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力 ...

  6. 朝着理想坚实迈进_坚实原则:开放/封闭原则

    朝着理想坚实迈进 先前我们讨论了单一责任原则. 关于实体原则首字母缩写, 打开/关闭原则是该行中的第二个原则. "软件实体(类,模块,功能等)应打开以进行扩展,但应关闭以进行修改" ...

  7. 坚实原则:开放/封闭原则

    先前我们讨论了单一责任原则. 关于实体原则首字母缩写, 打开/关闭原则是该行中的第二个原则. "软件实体(类,模块,功能等)应打开以进行扩展,但应关闭以进行修改" 通过采用该原理, ...

  8. 开放封闭原则_开放/封闭原则

    开放封闭原则 I have to admit the first time I peeked at the academic definition of the Open/Closed Princip ...

  9. 设计一个扩展自抽象类geometricobject的新的triangle类_面向对象设计原则之开放封闭原则(开闭原则OCP)...

    (1) 定义 一个软件实体(类.模块.函数等),对于扩展是开放的,对于更改是封闭的. 对于扩展是开放的:这意味着模块的行为是可以扩展的.当应用的需求发生改变时,我们可以对模块进行扩展,比如增加新的类或 ...

  10. C++设计模式-开放-封闭原则基本概念与实例

    目录 基本概念 举一个例子 基本概念 在如那就的设计模式中,不能修改,但可以扩展的实现是一条十分重要的原则,它是开放-封闭原则(The Open-Clossed Principle,简称OCP)或开- ...

最新文章

  1. 曙光高性能集群系统管理员手册(链接)
  2. C++设计模式实例图解
  3. 小程序向Java传值,微信小程序 页面传值详解
  4. python需要配置环境变量吗_python安装和配置环境变量
  5. 网络爬虫中的Unicode码解决[实例]
  6. 电影《姜子牙》要被改编成游戏了 期待吗?
  7. 95-40-055-java.util.concurrent-ConcurrentSkipListSet
  8. python 字符串详解
  9. android学习-1
  10. 常用电脑软件你选对了吗?(知道的不知道的,这些软件每个都值得你安装)
  11. 新世纪大学英语(第二版)综合教程第一册 Unit 3 重点单词
  12. Mybatis-Plus入门(一)
  13. 吐血推荐一大波让你直呼哇塞的Canvas库
  14. 我被选中为TOM邮箱6.0新版体验官
  15. Java项目:基于jsp+ssm乐轩公司订餐系统(计算机毕业设计)
  16. 什么是面形误差PVr?【光学测量、光学设计必看】
  17. 在Matlab中构建最大带权生成树
  18. Metasploit上使用RPC方式复现一个Linux提权漏洞
  19. php中斜杠是什么,php加斜杠的转义方法
  20. python 面向对象理解_怎么理解面向对象?

热门文章

  1. mysql的配置和安装
  2. 如何通过电子邮件营销吸引客户
  3. win修改命令行php版本,如何修改php版本
  4. unity 获取字符串长度及获取不重复数字
  5. 基于javaee珠宝购物网站的设计
  6. ubuntu鼠标变成十字,不能操作的解决
  7. ffmpeg之封装格式之aac
  8. 用户管理系统python_当用户管理系统遇上python和mongodb后……
  9. CAD中如何将底图变成单一的颜色?
  10. delphi 自动关联外部程序 打开文件_小程序跳转最全使用手册