文章示例代码
你也可以在这些平台阅读本文:
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
开闭原则强调的是用抽象构建框架,用实现来扩展细节。
笔者这里以超市中的商品做一个简单的示例来方便理解。
首先创建一个商品接口,同时在接口内部定义获取商品ID、名称、价格的各个方法。一般来说,一个商品是一个实体,后续我们可以去写一个类包含商品ID、名称、价格这三个成员变量,这里仅仅为了演示开闭原则。
/**
* @author zhh
* @description 商品接口
* @date 2020-02-04 22:47
*/
public interface IGoods {
/**
* 获取商品ID
*/
Integer getId();
/**
* 获取商品名称
*/
String getName();
/**
* 获取商品价格
*/
Double getPrice();
}
我们的商品其实是有很多分类的,比如食品、用品、电器等等。
下面笔者以食品为例,创建食品类的同时实现商品接口。
/**
* @author zhh
* @description 食品类
* @date 2020-02-04 23:42
*/
public class Food implements IGoods {
private Integer id;
private String name;
private Double price;
public Food(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;
}
}
/**
* @author zhh
* @description 测试类
* @date 2020-02-04 23:57
*/
public class Test {
public static void main(String[] args) {
IGoods iGoods = new Food(1, "巧克力", 9.9);
String msg = String.format("商品ID: %s, 商品名称: %s, 商品价格: %s",
iGoods.getId(), iGoods.getName(), iGoods.getPrice());
System.out.println(msg);
}
}
测试类的输出结果如下:
商品ID: 1, 商品名称: 巧克力, 商品价格: 9.9
假设现在超市进行一系列的商品促销活动,全场食品类的商品打6折,那我们如何来实现这个需求?
针对上述的场景示例,我们想当然地会进行如下的改动,既快速又方便。
/**
* @author zhh
* @description 商品接口
* @date 2020-02-04 22:47
*/
public interface IGoods {
// 此处省略其余方法
// 新增 获取商品折扣价格 方法
Double getDiscountPrice();
}
/**
* @author zhh
* @description 食品类
* @date 2020-02-04 23:42
*/
public class Food implements IGoods {
// 此处省略其余方法
// 子类实现该方法
public Double getDiscountPrice() {
return getPrice() * 0.6;
}
}
上述简单的小改动,看样子确实是满足了我们的需求,但是仔细观察你会发现,这种改动不仅修改了接口,同时也对具体的实现类也进行了改动。
问题也就来了。假设我们商品分类有很多,那么所有的商品实现类都需要去实现接口新增的方法。而接口作为一种契约,是不应该经常变化的,它应该是稳定且可靠的。
通过扩展新建一个食品的子类用来处理食品类打折,覆写食品类获取价格的方法,同时提供一个获取商品原价的方法。
/**
* @author zhh
* @description 食品打折类
* @date 2020-02-05 00:27
*/
public class FoodDiscount extends Food {
public FoodDiscount(Integer id, String name, Double price) {
super(id, name, price);
}
public Double getOriginPrice() {
return super.getPrice();
}
@Override
public Double getPrice() {
return this.getOriginPrice() * 0.6;
}
}
/**
* @author zhh
* @description 测试类
* @date 2020-02-04 23:57
*/
public class Test {
public static void main(String[] args) {
IGoods iGoods = new FoodDiscount(1, "巧克力", 9.9);
FoodDiscount foodDiscount = (FoodDiscount) iGoods;
String msg = String.format("商品ID: %s, 商品名称: %s, 商品原价: %s, 商品折后价: %s",
foodDiscount.getId(), foodDiscount.getName(), foodDiscount.getOriginPrice(), foodDiscount.getPrice());
System.out.println(msg);
}
}
测试类的输出结果如下:
商品ID: 1, 商品名称: 巧克力, 商品原价: 9.9, 商品折后价: 5.94
提高软件系统的可复用性和可维护性