开闭原则(Open_Close Principle,OCP)是指一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。
强调的是用抽象对象构建框架,用实现扩展细节
开闭原则,是面向对象设计中,最基础的设计原则。它知道我们如何建立稳定灵活的系统。
例如:我们版本更新,尽可能不修改源代码,但是可增加新功能。
假如我们使用出售电脑为例,首先定义一个顶层接口Computer:
/**
* @Description: 顶层接口,定义了获取电脑信息的接口方法
* @aouthor Geoffrey·Archie
* @create 2020-09-25 14:40
*/
public interface Computer {
double getPrice(); // 获取价格
String getColor(); // 获取颜色
int getMemory(); // 获取内存
float getSize(); // 尺寸
}
然后定义两个实现类,华硕电脑与苹果Mac
/**
* @Description: 华硕
* @aouthor Geoffrey·Archie
* @create 2020-09-25 14:40
*/
public class AsusComputer implements Computer {
private double price;
private String color;
private int memory;
private float size;
// 有参构造参数
public AsusComputer(double price,String color,int memory,float size){
this.price = price;
this.color = color;
this.memory = memory;
this.size = size;
}
@Override
public double getPrice(){
return this.price;
}
@Override
public double getColor(){
return this.color;
}
@Override
public double getMemory(){
return this.memory;
}
@Override
public double getSize(){
return this.size;
}
}
/**
* @Description: Mac
* @aouthor Geoffrey·Archie
* @create 2020-09-25 14:40
*/
public class MacComputer implements Computer {
private double price;
private String color;
private int memory;
private float size;
// 有参构造参数
public MacComputer(double price,String color,int memory,float size){
this.price = price;
this.color = color;
this.memory = memory;
this.size = size;
}
@Override
public double getPrice(){
return this.price;
}
@Override
public double getColor(){
return this.color;
}
@Override
public double getMemory(){
return this.memory;
}
@Override
public double getSize(){
return this.size;
}
}
测试类
public class Test {
public static void main(String[] args){
Computer computer = new AsusComputer(4888.88D,"深空灰",8,14.0F);
System.out.println(
"电脑:华硕\n" +
"售价: " + computer.getPrice() + "\n" +
"颜色: " + computer.getColor() + "\n" +
"内存: " + computer.getMemory() + "\n" +
"尺寸: " + computer.getSize() + "\n"
);
}
}
电脑:华硕
售价:4888.88
颜色:深蓝
内存:8
尺寸:14.0
这是我们一开始的需求,但是随着软甲发布运行,我们需求不可能是一成不变,肯定要接轨市场。假设现在是双十一,需要搞促销活动。那么我们代码肯定要添加新的功能。可能有些人会在原有的代码上做变动:
@Override
public double getPrice() {
return this.price * 0.6;
}
这是不符合开闭原则的,虽然看起来这样做最直接,也最简单,但是绝大部分项目中,一个功能的实现远比想象要复杂的多,我们在原有的代码中进行修改,其风险远比扩展和实现一个方法要大的多。
正确的做法可以这样,遵循对扩展开发,对修改关闭:
/**
* @Description: 华硕电脑打折
* @aouthor Geoffrey·Archie
* @create 2020-09-25 14:40
*/
public class AsusDiscountComputer extends AsusComputer {
private float discount;
public AsusDiscountComputer(double price,String color,int memory,float size,float discount){
super(price,color,memory,size);
this.discount = discount;
}
public double getDiscountPrice() {
return getPrice() * this.discount;
}
}
实现一个关于折扣的子类,其中包含一个关于折扣的方法,这方法相当于一个扩展方法,可以看到这个子类是AsusComputer的,那为什么不把他设计成一个公用的折扣类呢,比如DisCountComputer,所有实现类都继承这个折扣类。这是因为每种实现类的折扣方案可能是不一样的。所以我们最好能把它作为每个实现类的子类单独实现。如果你能确保你的业务的功能能兼容所有相关联的需求你也可以公用同一个。
public class Test1 {
public static void main(String[] args){
Computer computer = new AsusDiscountComputer(4888.88D,"深空灰",8,14.0F,0.5F);
AsusDiscountComputer asusDiscountComputer = (AsusDiscountComputer)computer;
System.out.println(
"电脑:华硕\n" +
"原售价: " + asusDiscountComputer.getPrice() + "\n" +
"打折后售价: " + asusDiscountComputer.getDiscountPrice() + "\n" +
"颜色: " + asusDiscountComputer.getColor() + "\n" +
"内存: " + asusDiscountComputer.getMemory() + "\n" +
"尺寸: " + asusDiscountComputer.getSize() + "\n"
);
}
}
电脑:华硕
原售价:4888.88
打折后售价:2444.44
颜色:深蓝
内存:8
尺寸:14.0
你可以看到如果想要调用getDiscountPrice()方法,在原有的基础上你还要对他强转,如果你能确定新扩展的需求,能兼容原有的继承体系,也可以把它抽取到顶层的Computer接口中。
最后看一下继承体系
上面只是一个很简单的示例,在实际开发工程中,并不是一定要求所有代码都遵循设计原则,我们要考虑人力、时间、成本、质量,不用刻意追求完美,要在适合的场景遵循设计原则,体现的是一种平衡取舍,帮助我们设计出更加优雅的代码结构