设计原则--开闭原则

Antvictor大约 2 分钟架构设计原则

我是Ant,今天学习的是设计原则之一的开闭原则(Open Closed Principe, OCP)。

什么是开闭原则?

开闭原则的定义是:对修改关闭,对扩展开放。 开闭原则是最基础的设计原则。

为什么使用开闭原则呢?

我们假设一个场景:程序员小A开发了一个查询年月日的项目,别人可以直接使用他的Jar调用对应的接口查询。

有一天小A将这个接口修改了,不再返回年月日,而只返回年。那么使用的人如果升级了这个Jar之后,业务逻辑是不是就出现问题了呢?

如果小A想要一个只返回年的接口,那么他可以新增加一个,这样既不影响原业务逻辑,也扩展了新功能。

所以我们要对修改关闭,对扩展开放。

示例

假设我们有一个商品对象,商品包含了价格、名称等。

public class Goods{
	private String name;
	private Double price;

	Goods(String name, Double price) {
		this.name = name;
		this.price = price;
	}

	public void getPrice() {
		return price;
	}
	public void getName() {
		return name;
	}
}

现在有了一个新业务,我们需要对商品进行打折,如果我们直接修改getPrice(), 那么我们可能再需要原价的时候就没有了入口,或者修改再修改代码,这样做系统明显不健壮,也不符合开闭原则:

public void getPrice() {
	return price * 0.6;
}

那么符合的做法是什么呢? 原接口不变,新增一个接口?

public void getDiscountsPrice(){
	return price * 0.6;
}

如果这么做的话,看起来是符合的,但我们需要去修改对应的业务逻辑,比如:

public class GoodsTest{
	public static void main(String[] args) {
		Goods goods = new Goods("苹果", 5.0);
		int num = 5;
		System.out.println("买了" + num + goods.getName() + ", " +
                "总价:" + getTotalPrice(goods, num));
	}

	/**
	* 查询购买指定数量的商品总价
	*/
	public static Double getTotalPrice(Goods goods, int num) {
		return goods.getPrice() * num;
	}
}

这种情况下,我们就需要将每个goods.getPrice()修改成goods.getDiscountsPrice(), 上面的例子中只有一个,但如果是有很多呢?要知道就算我们不改,代码也是不会报错的,但结果却不是我们想要的了。 那么有没有更好的办法呢? 使用继承,不修改原对象,在新对象中修改价格

public class GoodsDiscounts extends Goods {
	GoodsDiscounts(String name, Double price) {
		super(name, price);
	}

	public Double getPrice() {
		super.getPrice() * 0.6;
	}
	public Double getOriginPrice() {
		super.getPrice();
	}
}

这样我们只需要将GoodsTest中的new Goods修改即可

Goods goods = new GoodsDiscounts("打折苹果", 5.0);

这样就万事大吉了...吗? 其实不然,这里虽然暂时符合了开闭原则,但违背了另一个原则:里氏替换原则

那么具体怎么操作让上面的代码都符合呢?我们下回分解。