系列文章|源码
https://github.com/tyronczt/design-mode-learn
定义-是什么
开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的。
Software entities like classes,modules and functions should be open for extension but closed for modifications 一个软件实体, 如类, 模块, 函数等应该对扩展开放, 对修改封闭.
这也是开放封闭原则的核心思想:对扩展开放,对修改封闭。
思考-为什么
在需求不断变化的软件设计过程中 ,如何保障系统的稳定性及可维护性,开闭原则至关重要,即多拓展,少修改。
作用
- 减少测试成本。只需测试拓展的代码逻辑,减少对原有代码的功能测试;
- **提高复用性。**开闭原则的思路使程序设计更加原子性,粒子越小,复用的可能性越大;
- **提高可维护性。**面向对象开发的要求;
应用-怎么用
使用开闭原则的方式
1、抽象约束
一,通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法;
二,参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;
三,抽象层尽量保持稳定,一旦确定即不允许修改。
2、元数据(metadata)控制模块行为
元数据就是用来描述环境和数据的数据,通俗地说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。 Spring容器就是一个典型的元数据控制模块行为的例子,其中达到极致的就是控制反转(Inversion of Control)。3、封装变化
对变化的封装包含两层含义:
一,将相同的变化封装到一个接口或者抽象类中;
二,将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。
4、制定项目章程
在一个团队中,建立项目章程是非常重要的,因为章程中指定了所有人员都必须遵守的约定,对项目来说,约定优于配置。案例分析
案例:支付业务
需求:商城系统,用户买好东西后,准备付款,支持支付宝、微信、银行卡支付。
代码仓库地址:https://github.com/tyronczt/design-mode-learn/tree/main/design-mode-learn-2-01
原始代码
public enum PaymentTypeEnum {
ALI_PAY("AliPayment"),
WECHAT_PAY("WechatPayment"),
BANK_PAY("BankPayment");
}
public interface IPayBusinessService {
void payOperate(PaymentMethodsEnum type, UserInfo userInfo);
}
public class PayBusinessSerivceImpl implements IPayBusinessService {
@Override
public void payOperate(PaymentMethodsEnum type, UserInfo userInfo) {
// 支付宝
if (type == PaymentTypeEnum.ALI_PAY) {
System.out.println("正在支付宝付款...");
} else if (type == PaymentTypeEnum.WECHAT_PAY) {
System.out.println("正在微信付款...");
} else if (type == PaymentTypeEnum.BANK_PAY) {
System.out.println("正在银行卡付款...");
}
}
}
上述代码实现, 虽然满足了业务需求,但是后期维护会比较麻烦。主要原因是:
①作为支付这样的核心业务逻辑,相对比较复杂,都在一个方法内实现,这个方法会很庞大,不利于排查问题;
②支付方式随着业务的发展也会增加,新支付方式的增加会应该整个业务逻辑,增加测试成本,不利于系统的稳定性;
改进方案
public class Pay {
private PaymentTypeEnum paymentTypeEnum;
public PaymentTypeEnum getPaymentTypeEnum() {
return paymentTypeEnum;
}
public void setPaymentTypeEnum(PaymentTypeEnum paymentTypeEnum) {
this.paymentTypeEnum = paymentTypeEnum;
}
}
public interface IPaymentService {
void pay(Pay pay);
}
public class AliPaymentServiceImpl implements IPaymentService{
@Override
public void pay(Pay pay) {
System.out.println("正在支付宝付款...");
}
}
public class WechatPaymentServiceImpl implements IPaymentService{
@Override
public void pay(Pay pay) {
System.out.println("正在微信付款...");
}
}
public class BankPaymentServiceImpl implements IPaymentService{
@Override
public void pay(Pay pay) {
System.out.println("正在银行付款...");
}
}
改进方案将不同支付方式通过不同的类来实现支付逻辑,修改逻辑不会对原有代码产生影响,同时也把公用的支付逻辑进行抽离。
此处只是简单的实现,在真实生产代码中还会结合工厂、策略模式等,将支付方式在项目启动时注入工厂类中,在使用具体策略时,只需从工厂类中拿到对应策略的实现类即可完成相应逻辑。
参考
设计模式六大原则(六)----开闭原则
如何正确理解策略模式?开闭原则是关键!