P2:开闭原则(OCP)

一、开闭原则简介

开闭原则Open-Closed Principle,简称OCP,是面向对象的可复用设计中最重要的设计原则,具体定义如下:一个系统应当对扩展开放,对修改关闭,即软件系统应在不修改原有功能代码的情况下进行扩展(非必要时不轻易修改原有功能实现)。

遵循开闭原则的好处:
1、测试复用性:不影响原有的测试代码,只需对扩展部分的代码进行增量测试即可;
2、功能复用性:提高代码的复用性,避免陷入重复造轮子的倾向;
3、维护成本:提高系统的可维护性,降低运维成本;

二、如何使用开闭原则;

1、面对抽象编程:

1)在构建系统架构的时候,按接口类来划分功能,定义好接口的功能边界,与接口定义无关的功能不允许放在接口中;
2)参数以及引用对象一律使用接口,而不是实现类;
3)接口抽象层保持稳定,不允许随意修改;

2、元数据控制模块行为:

元数据(metadata)被定义为:描述数据的数据,对数据及信息资源的描述性信息。
通俗来说就是通过配置文件来操作数据,Spring容器的控制反转(Inversion of Control)就是一个典型的元数据控制模块行为的例子。
比较接近开发思维的解读就是:类似变量的定义,我们通过使用配置参数来操作功能和数据,而不是直接更改接口实现类。

3、约定优先:

约定优于配置,我们在一个项目中事先建立项目章程,使用章程中指定了所有开发人员都必须遵守的约定,避免在后续的开发过程中出现功能或其他规范的越界行为。

4、封装变化

封装变化,找出预计的变化或不稳定的点,为这些变化点创建稳定的接口,准确的讲是封装可能发生的变化。开闭原则只是一个理想的状态,它和物理学上“没有摩擦”很类似,任何系统都无法百分之百做到“开闭”。但是,只要我们要朝着这个方向前进,就可以显著的改善一个系统的架构,真正做到"拥抱变化"。

对变化的封装包含两层含义:
第一,将相同的变化封装到一个接口中;
第二,将不同的变化封装到不同的接口中,不应该有两个不同的变化出现在同一个接口或抽象类中。

三、案例分析

假设某系统有一个支付功能,现有的支付方式有支付宝、微信支付,后期可能还有银联支付、易支付等等,原始的设计方案如下:


// 客户端调用-选择支付手段
public class CommonPay {
 
    void pay(String mode){
        if(mode.equals("ali")){
            AliPay aliPay = new AliPay();
            aliPay.pay();
        }else if(mode.equals("wx")){
            WXPay wxPay = new WXPay();
            wxPay.pay();
        }
    }
}
// 支付宝支付
public class AliPay {
    public void pay() {
        //TODO 调用支付宝支付
    }
}
// 微信支付
public class WXPay{
    public void pay() {
        //TODO 调用微信支付
    }
}

在上面的实现中,通过 commonPay.pay( 支付类型参数 ) 的方式传入不同支付类型参数来调用对应的支付功能,如果我们要扩展银联支付、易支付等,就要对 commonPay.pay 的实现进行修改,不符合开闭原则。
我们按如下的方式进行一次改进:

public interface Pay {
    // 支付
    void pay();
}
public class AliPay implements Pay {
    @Override
    public void pay() {
        //TODO 调用支付宝支付
    }
}
public class WXPay implements Pay{
    @Override
    public void pay() {
        //TODO 调用微信支付
    }
}
// 客户端调用-选择支付手段
public class CommonPay {

    @Autowired
    Pay payMode;
    void pay(Pay payMode){
        payMode.pay();
    }
}

按这个模式,如果需要扩展银联支付,我们新增一个 UnionPay 的实现类,在CommonPay 的调用中传入payMode=UnionPay 对象给pay方法即可:

public class UnionPay implements Pay{
	//TODO 
}

END.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章