开闭原则的含义
开闭原则是面向对象设计中的重要原则之一,其名称来源于 Bertrand Meyer 在 1988 年的著作《Object-Oriented Software Construction》中,意为“对扩展开放,对修改关闭”,简称 OCP 原则。
它是指软件中的对象(类、模块、函数等)应该对扩展开放,对修改关闭,即应该在不修改原有代码的情况下实现对其行为、功能的增加、扩展和改进。
之所以说这条原则比较重要,是因为扩展性是代码质量最重要的衡量标准之一。在设计模式中,大部分都是为了提高代码的扩展性而存在的,而这些设计模式中主要遵从开闭原则的设计原则。
如何理解开闭原则
开闭原则的目的是为了让我们的软件系统更加灵活、可扩展、可维护。在实际开发中,我们往往会遇到需求的变更,比如添加新的功能、修改某个功能的实现方式等等。
如果我们的代码没有遵循开闭原则,那么一旦需求的变更就会导致代码的修改,这不仅会增加代码风险,还会增加我们的开发、测试和维护成本。
而遵循开闭原则,则可以让我们的代码更容易地应对需求的变更,而不需要对原有代码做出修改或只做出最小限度的修改。这将减少代码风险,提高开发效率,同时也使得代码更加易于维护和扩展。
所以,在平时开发中,如果需要添加一个新的功能,应该是通过在已有代码基础上扩展代码,比如新增模块、类、方法、属性等,而不是修改已有模块代码的方式来实现。但是,我们需要注意的是:
- 开闭原则并不是说完全不做任何修改,而是以最小的代价修改代码来完成新功能的开发
- 修改和扩展是相对的,在粗粒度不同的情况下,同样的代码改动,可能被认定为“修改”,也有可能被理解为“扩展”
如何才能做到开闭原则
在实现“对扩展开放、修改关闭”设计原则前,需要考虑以下几个方面的问题:
- 梳理系统需求和功能:需要充分理解系统的需求和功能,并将其划分为具体的模块,以便后续的扩展和修改能够有条不紊地进行。
- 定义系统接口:定义系统的接口,包括输入输出接口、数据接口、消息接口等,这些接口应该是稳定且易用的,以满足后续的扩展和修改需求。
- 选择合适的设计模式:选择合适的设计模式,例如面向对象编程中的继承、接口、抽象类等,以便能够方便地进行扩展和修改。
- 制定设计规范:制定系统的设计规范,明确每个模块的职责和功能,以及模块之间的相互依赖关系,保证系统的稳定性和可维护性。
- 编写可测试性代码:编写可测试性代码,以便后续进行单元测试、集成测试等软件测试工作,提高代码质量和可维护性。
可见,在实现“对扩展开放、修改关闭”设计原则前,需要充分了解系统的需求和功能,并考虑稳定的接口、合适的设计模式、规范的设计文档以及高质量的可测试代码等因素。
下面我们用 Golang 简单实现开闭原则的代码,其实现方法通常有两种:通过接口实现和通过抽象类实现。
通过接口实现
我们可以通过定义接口来实现开闭原则,具体方法是:
1)定义一个接口,包含一些必需实现的方法。
type Payment interface {
Pay(amount float64) bool
}
2)定义结构体去实现该接口的方法,这里我们定义了两个结构体实现了 Payment 接口。
type Wechat struct{}
func (w Wechat) Pay(amount float64) bool {
return true
}
type Alipay struct{}
func (a Alipay) Pay(amount float64) bool {
return true
}
这样,当我们需要新增支付方式时,只需要定义一个新的结构体,并实现 Payment 接口的方法即可。
通过抽象类实现
我们可以通过定义抽象类来实现开闭原则,具体方法是:
1)定义一个抽象类,实现一些必需的方法。
type BaseHandler interface {
Handle(request Request) Response
}
2)定义一个具体的类去实现抽象类的方法。
type ConcreteHandler struct {
next BaseHandler
}
func (c *ConcreteHandler) Handle(request Request) Response {
if c.next == nil {
return nil
}
return c.next.Handle(request)
}
这样,当我们需要扩展 BaseHandler 时,只需要定义一个新的具体类并实现 Handle 方法,同时将其设置为 ConcreteHandler 的 next 即可。
项目设计中,使用开闭原则需要注意的点
在实际项目设计中,使用开闭原则需要注意以下几点:
- 合理设计结构和接口,避免出现类之间的耦合过高。
- 需要合理使用抽象类和接口,避免抽象类和接口过多的嵌套使用。
- 需要注意扩展的方向是否正确,避免扩展出现违反现有设计原则的风险。
- 需要充分考虑代码的可读性、可维护性和可扩展性,避免设计出难以维护和扩展的代码。
总结
开闭原则是面向对象设计中的重要原则之一,它可以帮助我们设计出更加灵活、可维护和可扩展的软件系统。
在实际开发中,我们可以通过定义抽象类和接口等方法来实现开闭原则,并需要注意合理设计结构和接口,充分考虑代码的可读性、可维护性和可扩展性,以及设计扩展的方向是否正确等问题。