java开闭原则 open-closed principle
基本知识
1.核心思想:面向抽象编程
2.基本内涵:对修改关闭,对扩展开放
3.要求:尽可能不修改源码而是增加新功能
例子
以spring5核心原理与30个类手写实战中的为例
package com.gupaoedu.vip.design.principle.openclose;/*** Created by Tom*/
public interface ICourse {Integer getId();String getName();Double getPrice();
}
package com.gupaoedu.vip.design.principle.openclose;/*** Created by Tom*/
public class JavaCourse implements ICourse{private Integer Id;private String name;private Double price;public JavaCourse(Integer id, String name, Double price) {this.Id = id;this.name = name;this.price = price;}public Integer getId() {return this.Id;}public String getName() {return this.name;}public Double getPrice() {return this.price;}}
package com.gupaoedu.vip.design.principle.openclose;/*** Created by Tom*/
public class JavaDiscountCourse extends JavaCourse {public JavaDiscountCourse(Integer id, String name, Double price) {super(id, name, price);}public Double getDiscountPrice(){return super.getPrice() * 0.61;}// public Double getOriginPrice(){
// return super.getPrice();
// }
//
// public Double getPrice(){
// return super.getPrice() * 0.61;
// }}
package com.gupaoedu.vip.design.principle.openclose;/*** Created by Tom.*/
public class OpenCloseTest {public static void main(String[] args) {ICourse iCourse = new JavaDiscountCourse(232, "【咕泡学院】Java架构师专题课", 11800D);JavaDiscountCourse javaCourse = (JavaDiscountCourse) iCourse;System.out.println("课程ID:" + javaCourse.getId() +"\n课程名称:《" + javaCourse.getName() + "》" +"\n原价:" + javaCourse.getPrice() + "元" +"\n折后价:" + javaCourse.getDiscountPrice() + "元");// ICourse iCourse = new JavaDiscountCourse(232, "【咕泡学院】Java架构师专题课", 11800D);
// JavaDiscountCourse javaCourse = (JavaDiscountCourse) iCourse;
// System.out.println("课程ID:" + javaCourse.getId() +
// "\n课程名称:《" + javaCourse.getName() + "》" +
// "\n原价:" + javaCourse.getOriginPrice() + "元" +
// "\n折后价:" + javaCourse.getPrice() + "元");}
}
这里的javaDiscountCourse就是继承了javaCourse,实现功能拓展,新增了一个折扣功能
至于注释掉的getPrice()方法
// public Double getPrice(){
// return super.getPrice() * 0.61;
// }
也是符合开闭原则的,因为它通过重写父类方法来改变行为,而没有修改父类。在这种情况下,JavaDiscountCourse 就不仅仅是拓展,而是改变了父类行为。
不过具体场景推荐使用getDiscountPrice(),因为职责单一清晰,getPrice()方法表示原始价格,getDisountPrice表示折扣价格,职责分离,代码更清晰易懂
,同时也可以避免歧义,getPrice()如果也可能获得打折价格,则可能让调用者混乱。
总体上:JavaDiscountCourse 通过继承并新增方法的方式,在不修改 JavaCourse 现有代码的基础上,实现了获取打折价格的功能,完美体现了开闭原则的精神
对于测试类中的方法:
JavaDiscountCourse javaCourse = (JavaDiscountCourse) iCourse; // 这里进行了向下转型
这里进行了向下转型,为了调用 JavaDiscountCourse 特有的 getDiscountPrice() 方法,不得不将 ICourse 类型的引用强制转换为 JavaDiscountCourse 类型。缺点来说,一方面破坏了原本的多态,毕竟使用javaDiscountCourse赋值给ICourse目的是为了使用多态,但是向下转型则退化了这种优势。而且也可能导致ClassCastException,需要判断对象是不是对应的类的实例。此外,getDiscountPrice()方法紧耦合于类javaDiscountCourse,不利于统一管理。
我们借鉴之前注释的getPrice方法,既然获取价格这种需求是很常见的,那么我们自然可以抽象到接口中。我们为了避免混淆,可以换个名字:
比如getActualPrice(),即获取实际价格
public interface ICourse {Integer getId();String getName();Double getPrice(); // 原始价格Double getActualPrice(); // 新增方法:获取实际支付价格 (可能是原价,也可能是优惠价)
}public class JavaCourse implements ICourse {// ...@Overridepublic Double getActualPrice() {return getPrice(); // 对于原价课程,实际价格就是原价}
}public class JavaDiscountCourse extends JavaCourse {// ...@Overridepublic Double getActualPrice() {return super.getPrice() * 0.61; // 对于打折课程,实际价格是折后价}
}
这样,在 OpenCloseTest 中,只需要:
ICourse iCourse = new JavaDiscountCourse(232, "【咕泡学院】Java架构师专题课", 11800D);
System.out.println("课程ID:" + iCourse.getId() +"\n课程名称:《" + iCourse.getName() + "》" +"\n原价:" + iCourse.getPrice() + "元" +"\n实际支付价:" + iCourse.getActualPrice() + "元");
// 这里就不需要向下转型了,因为 getActualPrice() 是接口方法