系列文章|源碼
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("正在銀行付款...");
}
}
改進方案将不同支付方式通過不同的類來實作支付邏輯,修改邏輯不會對原有代碼産生影響,同時也把公用的支付邏輯進行抽離。
此處隻是簡單的實作,在真實生産代碼中還會結合工廠、政策模式等,将支付方式在項目啟動時注入工廠類中,在使用具體政策時,隻需從工廠類中拿到對應政策的實作類即可完成相應邏輯。
參考
設計模式六大原則(六)----開閉原則
如何正确了解政策模式?開閉原則是關鍵!