在面向对象编程领域,开闭原则(The Open/Closed Principle,OCP )、“软件中的对象”类、模块、函数等)对于扩展应该是开放的
扩展意味着是允许在不改变它的源代码的前提下变更它的行为的实体。 在需要通过代码审核、单元测试等确保产品使用质量的过程来更改源代码的产品化环境中,此特性尤其有价值。 不需要以上步骤,因为遵循此原则的代码在扩展时不会更改。
开闭原则的命名应用于两种方式。 这两种方式都使用继承解决了明显的困境,但它们的目的、技术和结果不同。
鲤鱼冥王星开关原则
yxdyc一般被认为是最早提出开闭原则这一术语的人,[来源请求]在他1988年发行的《面向对象软件构造》中给出。 这个想法是一旦完成一个类的实现只应该因错误而修改,新的或者改变的特性应该通过新建不同的类实现。新建的类可以通过继承的方式来重用原类的代码。衍生的子类可以或不可以拥有和原类相同的接口。
鲤鱼的定义提倡实现继承。 具体实现可以通过继承方式重用,但接口规范不必如此。 现有实现已针对修改关闭,但新实现不需要实现原始接口。
多态开闭原则
在20世纪90年代,开关原则被广泛重新定义,通过抽象接口的使用,在此期间改变了实现,制作了多个实现,代替了多态的不同实现。
与鲤鱼冥王星的用法相比,多态开闭原则的定义提倡向抽象基类继承。 接口规约可以通过继承重用,但实现不需要重用。 现有接口对于修改是关闭的,需要新的实现,至少实现该接口。
GDdtd于1996年发表的文章《开闭原则》是使用这种方法的启发式著作。 2001年,Craig
Larman将开闭原则与Alistair Cockburn的“受保护的变量”(Protected )相关联
关于Variations模型和David Parnas信息隐藏的讨论。
思想抽象构建框架,实现扩展细节。
开闭原则的关键是抽象,抽象类/接口定义抽象层,具体类扩展。
例如:
工作中: 9小时弹性工作,9小时结构不变。 可变的是具体的上班和下班时间,确保9个小时就可以了。 这是开闭原则在生活中的应用。
解决了什么问题,作为序媛,大家有过类似的经历吗? 一个需求来了就必须更改一次代码。 这种方式已经不足为奇了。 虽然每个人每次只做了一点改动,但是经过长期的积累,又来了一个新的需求,改动量会很大。 在这个过程中,每个人都只是按照惯例修改,所以是无辜的。 但是,结果是所有人都受到了伤害,代码越来越难维护。
“修改”会带来这么多问题,我们可以不修改吗? 开放原则提供了这样一个新的方向。
开关原则是最重要的原则之一,其他一些原则是其体现或扩展,开关原则的优点是提高了程序的复用性、可维护性。
代码应用要求
“我”转任java课程讲师,现在需要向用户展示课程信息(ID、课程名称、课程价格等)。
代码实现如下。 (以下代码部分没有规格,请作为参考。 )
publicinterfaceicourse { integer getid (; 字符串获取名称(; 双精度(; } publicclassjavacourseimplementsicourse { privateintegerid; 私有字符串名称; private Double price; publicJavacourse(integerid,String name,Double price ) { this.id=id; this.name=name; this.price=price; } @Override public Integer getId () { return this.id; } @Override public String getName () { return this.name; } @Override public Double getPrice () { return this.price; } public class test { publicstaticvoidmain (string [ ] args ) icoursejavacourse=newjavacourse (96,' Java ',34d ); System.out.println (课程ID:' javaCourse.getId )”课程名称: ' javaCourse.getName”课程价格
格: " + javaCourse.getPrice()); }} 类图 需求变更快双十一了,要进行课程的打折活动,如打5折,需要向用户展示打折后的课程价格 和 课程原价。
常规的方式是 在 接口 ICourse中新加 打折方法 的声明,在JavaCourse 类中新加打折方法的实现,最后在 客户端 test测试类 添加 打折方法 相关的内容。
那这种方式符合开闭原则么,显然是不符合的,需求的变更,使用这种方式 对原有的接口和类都进行了修改,而开闭原则是 对扩展开放,对修改关闭,那应该怎么做呢?
原有接口 ICourse 和 JavaCourse 类 不变,新增JavaDisCountCourse 类,同时在客户端添加 打折相关的内容即可。
JavaDisCountCourse类
public class JavaDisCountCourse extends JavaCourse { // 构造方法不动 public JavaDisCountCourse(Integer id, String name, Double price) { super(id, name, price); } // 获取原价 public Double getOriginPrice() { return super.getPrice(); } // 重写获取价格方法,好处:复用 @Override public Double getPrice() { // 还可根据需求在这加其他条件 return super.getPrice() * 0.5; }} public class Test { public static void main(String[] args) { ICourse javaCourse = new JavaCourse(96, "Java", 34d); System.out.println("课程ID:" + javaCourse.getId() + " 课程名称: " + javaCourse.getName() + " 课程价格: " + javaCourse.getPrice()); ICourse discountJavaCourse = new JavaDisCountCourse(97, "discountJava", 100d); Double originPrices = ((JavaDisCountCourse) discountJavaCourse).getOriginPrice(); System.out.println("打折课程ID:" + discountJavaCourse.getId() + " 打折课程名称: " + discountJavaCourse.getName() + " 打折课程价格: " + discountJavaCourse.getPrice() + " 原价: " + originPrices); }} 改后的类图那问题又来了,客户端 test 因为需求的改变修改了代码,不符合开闭原则,怎么解决呢,配置文件…
小结以不变应万变,设计模式的七大原则 正是 这 ”不变“。
设计模式,架构,框架
设计模式概览