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

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

定义

开闭原则(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技术与架构

相关推荐

  1. 面向对象设计原则

    2024-04-26 19:00:02       20 阅读
  2. 设计模式原则

    2024-04-26 19:00:02       44 阅读
  3. 软件设计原则-原则

    2024-04-26 19:00:02       36 阅读
  4. 软件设计原则原则

    2024-04-26 19:00:02       14 阅读
  5. 面向对象设计里氏替换原则

    2024-04-26 19:00:02       19 阅读
  6. 面向对象设计单一职责原则

    2024-04-26 19:00:02       24 阅读
  7. Python面向对象程序设计

    2024-04-26 19:00:02       45 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-26 19:00:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-26 19:00:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-26 19:00:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-26 19:00:02       20 阅读

热门阅读

  1. npm install CERT_HAS_EXPIRED解决方法

    2024-04-26 19:00:02       15 阅读
  2. BootLooder引导传参和镜像编译

    2024-04-26 19:00:02       15 阅读
  3. Git忽略文件

    2024-04-26 19:00:02       12 阅读
  4. ES6 新增功能复盘梳理

    2024-04-26 19:00:02       13 阅读
  5. python 学习笔记24 图片视频修复

    2024-04-26 19:00:02       11 阅读
  6. 掩码讲解,以及生成

    2024-04-26 19:00:02       13 阅读
  7. Nginx下php连接到GBase 8s数据库 - ODBC方式

    2024-04-26 19:00:02       28 阅读