SHOW ME THE CODE - 面向对象程序设计之 - 开闭原则(OCP)

SHOW ME THE CODE - 面向对象设计系列

今天我们为大家带来面向对象程序设计原则系列之 - 开闭原则

定义

开闭原则(Open/Closed Principle,OCP)是面向对象设计中最重要的原则之一,它规定:“软件实体(类、模块、函数等)应该对扩展开放,对修改封闭”。这意味着,一个实体应该能够通过扩展来满足新的需求,而不必修改其自身代码。

最早提出者
开闭原则最早是由美国计算机科学家伯特兰·迈耶(Bertrand Meyer)在1988年出版的著作《面向对象软件构造》(Object-Oriented Software Construction)中提出的。

理解

我们应该尽量通过扩展已有的代码来实现新功能,而不是修改已有的代码。这样可以降低对现有代码的影响,提高系统的可维护性和可扩展性。

扩展 VS 修改

  • 扩展
    有一点我们需要稍微理解一下,引入新的功能点,就必然会引入修改,扩展也是某种意义上的修改,只不过扩展是因为要引入一个新的逻辑,对原有代码的一点小小的改动,这是属于对原有逻辑的扩展,这是允许的。

  • 修改
    原则中提到的对修改关闭,不是不允许对代码做任何的改变,指的是:

    • 不修改核心业务逻辑
    • 不改变已有接口
    • 避免修改核心算法,核心数据结构

SHOW ME THE CODE

电商场景案例
假设我们有一个电商系统,其中有不同类型的商品,比如书籍、衣服和电子产品。我们需要计算订单的总价,并且每种商品都有不同的计价方式。

首先,我们设计一个接口 Product 来表示商品,其中包含一个方法用于计算商品的价格

interface Product {
    double getPrice();
}

然后,我们实现不同类型的商品类,比如书籍和衣服,注意例子中,书籍不打折,而衣服是打2折的,打折的逻辑写在了getPrice()方法里。

class Book implements Product {
    private double price;
    
    public Book(double price) {
        this.price = price;
    }
    
    public double getPrice() {
        return price;
    }
}

class Cloth implements Product {
    private double price;
    
    public Cloth(double price) {
        this.price = price;
    }
    
    public double getPrice() {
        return price * 0.2; // 衣服打 2 折
    }
}

现在,我们有了一个可扩展的商品系统,如果需要新增一种商品类型,只需要实现 Product 接口即可,比如增加一个Computer类实现Product接口,而不需要修改已有的代码。这符合开闭原则的要求。

但现在我们要引入一个新的功能,我们希望所有商品都能支持打折功能,且具体的折扣方案可能在将来还会变化。按照现在的代码,要支持这个功能,就需要修改具体的实现类,这显然是违反了开闭原则。

class Cloth implements Product {
       
    public double getPrice() {
    	double price = this.price;
        case 不同的打折活动
	        //618 促销
	        price = price * 0.5

			//双十一促销
			price = price * 0.1

		return price;
		
    }
}

怎么重构

为了符合开闭原则,我们可以通过引入抽象层来解耦商品和促销活动。我们可以定义一个抽象的 Discount 接口:

interface Discounter {
    double applyDiscount(double price);
}

增加具体的折扣类:

class EightyPercentDiscounter implements Discounter {
    public double applyDiscount(double price) {
        return price * 0.8;
    }
}

扩展原有产品类:

class Book implements Product {
    private double price;
    private Discounter discounter;
    
    public Book(double price) {
        this.price = price;
    }
    
 	//扩展性修改
 	public void setDiscounter(Discounter discounter)
 	{
 		this.discounter = discounter;
 	}
    
    public double getPrice() {
    	//扩展性修改
    	if (this.discounter == null) return price;
        return discounter.applyDiscount(price);
    }
}

class SalesActivity
{
	Product book = new Book(1.5);
	book.setDiscounter(new EightyPercentDiscounter());
	book.getPrice();
}

我们从这个例子中可以看到打折逻辑放到了具体的折扣类中,当我们还需要新增其它的折扣类时,产品类已经无需修改了,重构后的代码已经符合开闭原则了。

思考点

上面的例子只展示了片断,我们可以思考一下,现在流行的电商平台他们的折扣系统是如何实现的?欢迎关注我的公众号,留言和交流。

TXZQ聊IT技术与架构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值