开闭原则是指一个模块、类或函数应该对扩展开放、对修改关闭。它强调的是用抽象构建框架,用实现扩展细节,尽量在不修改原有代码的前提下进行扩展,这就需要我们使用接口和抽象类来实现预期效果。
我们举例说明什么是开闭原则,以菜品价格为例,我们来看一段代码。
首先,创建一个菜品接口IDishes:
public interface IDishes {
String getName();
double getPrice();
}
再创建一个实现IDishes接口的Hamburg类:
public class Hamburg implements IDishes {
private String name;
private double price;
public Hamburg(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String getName() {
return this.name;
}
@Override
public double getPrice() {
return this.price;
}
}
最后创建一个业务类Test,输出汉堡信息:
public class Test {
public static void main(String[] args) {
Hamburg hamburg = new Hamburg("香辣鸡腿堡", 10);
System.out.println("菜品名称:" + hamburg.getName() + "\t价格:" + hamburg.getPrice());
}
}
现在,我们要给汉堡做优惠活动,在原有的基础上打八折。目前解决方案有三种:
- 修改IDishes接口:在IDishes接口上加一个getDiscountPrice接口,专门获取打折后的价格。但是这样做的后果是,实现类Hamburg和业务类Test都要修改。接口应该是具有契约性的,不能频繁更改。
- 修改Hamburg实现类:直接修改Hamburg类的getPrice方法,返回打折后的价格,这样会导致原来的业务模块getPrice方法的业务逻辑发生了变化。
- 使用子类扩展实现:增加子类DiscountHamburg,重写父类Hamburg的getPrice方法,实现优惠活动的业务逻辑,这样做的好处是:原有代码中,只需要调整Test类的代码就可以了。
实现代码如下:
public class DiscountHamburg extends Hamburg {
public DiscountHamburg(String name, double price) {
super(name, price);
}
@Override
public double getPrice() {
return super.getPrice() * 0.8;
}
}
public class Test {
public static void main(String[] args) {
IDishes hamburg = new Hamburg("香辣鸡腿堡", 10);
System.out.println("菜品名称:" + hamburg.getName() + "\t价格:" + hamburg.getPrice());
IDishes discountHamburg = new DiscountHamburg("香辣鸡腿堡", 10);
System.out.println("菜品名称:" + discountHamburg.getName() + "\t折后价:" + discountHamburg.getPrice());
}
}
这样,在业务规则改变的情况下,我们通过扩展子类及修改高层模块(业务层)便足以应对改变的需求。利用开闭原则可以提高代码的复用性和可维护性,它要求我们尽可能通过扩展来实现需求,尽可能的不改变已有模块,特别的底层模块。