定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
强调:用抽象构建框架,用实现扩展细节。
优点:提高软件系统的可复用性及可维护性。
核心思想:面向抽象编程。
案例:
比如以水果店卖水果为例,主要的业务查询水果的名称及价格。
V1的版本中,设计如下:
public interface IFruit { Integer getId(); String getName(); Double getPrice(); }
水果的其中一个实现,苹果为例
public class Apple implements IFruit { private Integer Id; private String name; private Double price; public Apple(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; } }
但是随着业务的扩展,水果可能会进行打折促销,现在的设计就需要进行调整,有两种方式进行实现,一种是改动现有的接口和类,另一种是在现有的基础上进行扩展。
V2的第一种实现:
public interface IFruit { Integer getId(); String getName(); Double getPrice(); // 促销打折 Double getDiscountPrice(); }
public class Apple implements IFruit { private Integer Id; private String name; private Double price; public Apple(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; } @Override public Double getDiscountPrice() { return this.price*0.8; } }
这种方式很明显破坏了开闭原则,假如上下游的业务中有依赖到这个接口的,那相应的都要进行修改,影响面较大,维护的成本较高 。
V2的第二种实现,保持原有的设计,新增了苹果的折扣类:
public class AppleDiscount extends Apple { public AppleDiscount(Integer id, String name, Double price) { super(id, name, price); } public Double getDiscountPrice(){ return super.getPrice()*0.8; } }
通过这样去实现,符合我们的开闭原则,对原有的修改关闭,对新业务进行了扩展,修改后只会影响到新增的类,对原有的类不会有影响,应用侧修改相关的接口实现类即可。
当然,软件的开发中,没有绝对的对错,需要具体情况具体分析,开闭原则也有其缺点,比如可能会出现类爆炸的情况,类之间的关系比较复杂,耦合会比较严重。此案例只是想让大家更好的理解开闭原则,希望对大家的工作会有所帮助。