天天看點

寂然解讀設計模式 - 開閉原則

I walk very slowly, but I never walk backwards            

設計模式原則 - 開閉原則

​ 寂然

大家好,我是寂然~,本節課呢,我來給大家介紹設計模式原則之開閉原則,話不多說,我們直接進入正題,老規矩,首先帶大家了解一下開閉原則的官方定義,并作一個解釋,然後我們通過案例代碼來具體分析

官方定義

開閉原則( Open Close Principle ),又稱為OCP原則,他的官方定義如下:

Software entities like classes,modules and functions should be open for extension but closed for modifications.

一個軟體實體如類,子產品和函數應該對擴充開放,對修改關閉

基本介紹

對擴充開放指的是提供方,對修改關閉指的是調用方

一個軟體産品隻要在生命周期内,都會發生變化,即然變化是一個事實,我們就應該在設計時盡量适應這些變化,以提高項目的穩定性和靈活性,真正實作“擁抱變化”,開閉原則告訴我們應盡量通過擴充軟體實體的行為來實作變化,而不是通過修改現有代碼來完成變化,它是針對軟體的未來事件而制定的對現行開發設計進行限制的一個原則

案例示範 - 繪圖工具

OK,大家簡單了解過開閉原則後,我們來看如下一段代碼,幫助大家更深入的了解

有一個繪圖工具類,接收 Shape 對象,然後根據不同的 type,來繪制不同的圖形,具體代碼如下圖所示

//這是一個用于繪圖的類 [使用方]
class GraphicEditor {

    //接收 Shape 對象,然後根據不同的 type,來繪制不同的圖形
    public void drawShape(Shape s) {
        if (s.m_type == 1) {
            drawRectangle(s);
        } else if (s.m_type == 2) {
            drawCircle(s);
        }
    }
    //繪制矩形
    public void drawRectangle(Shape r) {

        System.out.println(" 正在繪制矩形中---繪制成功 ");

    }
    //繪制圓形
    public void drawCircle(Shape r) {

        System.out.println(" 正在繪制圓形中---繪制成功");

    }
}

//Shape 類,基類
class Shape {

    int m_type;
}

class Rectangle extends Shape {

    Rectangle() {
        super.m_type = 1;
    }
}
class Circle extends Shape {

    Circle() {
        super.m_type = 2;
    }

}           

上面這段代碼首先是可以完成需求的,OK,那現在我們新增繪制三角形的功能,大家想一下實作思路

首先我們要新增 Triangle 類,然後新增繪制三角形的方法, drawShap()方法裡添加判斷 并調用就Ok,新增代碼示例如下圖所示

//新增繪制三角形的子類
class Triangle extends Shape {
    Triangle() {
        super.m_type = 3;
    }
}
//類 GraphicEditor 中·添加判斷,type=3,繪制三角形
if (s.m_type == 1) {
    drawRectangle(s);
} else if (s.m_type == 2) {
    drawCircle(s);
} else if (s.m_type == 3) {
    drawTriangle(s); 
}

// 類 GraphicEditor 中新增繪制三角形的方法
public void drawTriangle(Shape r) {

    System.out.println(" 正在繪制三角形中---繪制成功 ");
}
           

案例分析

Ok,上面的代碼是比較好了解的,但是大家想一下,針對上面的業務邏輯來說,類 GraphicEditor 扮演的其實是調用方的角色,但是出現了新增的需求後,我們對于 類 GraphicEditor 進行了一系列改動,這顯然違背了ocp原則

因為我們上面提到,ocp原則對調用方的修改是關閉的,那大家想一下,新增繪制三角形的功能,我們還可以怎麼樣實作呢?下面我們在滿足ocp原則的情況下,對上面的代碼進行重構

解決方案

這時有的小夥伴說了,可以把建立 Shape 類做成抽象類,并提供一個抽象的 draw 方法,讓子類去實作即可,這樣我們有新的圖形種類時,隻需要讓新的圖形類繼承 Shape,并實作 draw 方法即可,使用方的代碼就不需要修 改了,這樣既滿足了業務邏輯,又符合開閉原則,具體代碼示例如下

//這是一個用于繪圖的類 [使用方]
class GraphicEditor {

    //接收 Shape 對象,然後根據不同的 type,來繪制不同的圖形
    public void drawShape(Shape s) {
        s.draw();
    }
}

//Shape變為抽象類,并提供抽象draw方法
abstract class Shape {

    int m_type;

    public abstract void draw();//抽象方法

}

class Rectangle extends Shape {

    Rectangle() {
        super.m_type = 1;
    }

    @Override
    public void draw() {
        System.out.println(" 正在繪制矩形中---繪制成功 ");
    }
}

class Circle extends Shape {

    Circle() {
        super.m_type = 2;
    }

    @Override
    public void draw() {
        System.out.println(" 正在繪制圓形中---繪制成功 ");
    }
}
           

OK,那這樣的話,同樣還是上面的需求,我們新增繪制三角形的功能,那我們隻需要建立一個 類Shape 的子類,實作draw() 方法即可,具體代碼示例如下

class Triangle extends Shape {

    Triangle() {
        super.m_type = 3;
    }

    @Override
    public void draw() {
        System.out.println(" 正在繪制三角形中---繪制成功 ");
    }
}           

案例總結

通過上面的重構,我們可以看到,當我們新增繪制三角形的功能,不需要修改調用方,即本案例中扮演調用方角色的類 GraphicEditor 不需要修改,而是擴充了提供方的類,來完成需求,就遵守了開閉原則,換句話說,開閉原則要求我們這樣做,即 針對提供方,對擴充開放,針對調用方,對修改關閉

注意事項

  • 開閉原則是程式設計中最基礎,最重要的設計原則,隻要是面向對象程式設計,在開發時都會強調開閉原則
  • 開閉原則是最基礎的設計原則,其它的五個設計原則都是開閉原則的具體形态,也就是說其它的五個設計原則是指導設計的工具和方法,而開閉原則才是其精神領袖。依照java語言的稱謂,開閉原則是抽象類,而其它的五個原則是具體的實作類
  • 開閉原則可以提高複用性和維護性

下節預告

OK,下一節,我們正式進入設計模式原則之迪 米特法則的學習,我會為大家用多個案例分析,來解讀設計模式原則之迪米特法則,以及它的注意事項和細節,最後,希望大家在學習的過程中,能夠感覺到設計模式的有趣之處,高效而愉快的學習,那我們下期見~