天天看點

【設計模式】四、面向對象設計原則之開閉原則

系列文章|源碼

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. 減少測試成本。隻需測試拓展的代碼邏輯,減少對原有代碼的功能測試;
  2. **提高複用性。**開閉原則的思路使程式設計更加原子性,粒子越小,複用的可能性越大;
  3. **提高可維護性。**面向對象開發的要求;

    應用-怎麼用

    使用開閉原則的方式

    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("正在銀行付款...");
    }
}
           

改進方案将不同支付方式通過不同的類來實作支付邏輯,修改邏輯不會對原有代碼産生影響,同時也把公用的支付邏輯進行抽離。

此處隻是簡單的實作,在真實生産代碼中還會結合工廠、政策模式等,将支付方式在項目啟動時注入工廠類中,在使用具體政策時,隻需從工廠類中拿到對應政策的實作類即可完成相應邏輯。

參考

設計模式六大原則(六)----開閉原則

如何正确了解政策模式?開閉原則是關鍵!

繼續閱讀