1. 程式人生 > >面向物件的設計模式(一)

面向物件的設計模式(一)

一、設計模式的概念

什麼是好的軟體設計?—— 複用!
◆  首先我們要先理解一個問題,什麼是模式? 
每一個模式描述了一個在我們周圍不斷重複發生的問題,以及該問題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重複勞動。 
◆  設計模式:也就是為了使程式碼的可複用,減少不必要的勞動;通常情況下,我們講的設計模式隱含地表示“面向物件設計模式”。(其中 可複用是目標,面向物件是手段,這兩點是設計模式的核心。)

二、面向物件的設計模式

變化是複用的天敵!面向物件設計最大的優勢 —— 抵禦變化!

(一)  “元件協作”模式

現代軟體專業分工之後的第一個結果是“框架與應用程式的劃分”,“元件協作”模式通過晚期繫結,來實現框架與應用程式之間的鬆耦合,是二者之間協作時常用的模式。

1.  Template Method模板方法

定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個演算法的結構即可重定義(override重寫)該演算法的某些特定步驟。 初始程式碼:
//程式庫開發人員
class Library {

    //穩定
    public void step1() {
        //...
    }

    //穩定
    public void step3() {
        //...
    }

    //穩定
    public void step5() {
        //...
    }

}
//應用程式開發人員
class Application {

    //變化
    public boolean step2() {
        //...
        return true;
    }

    //變化
    public void step4() {
        //...
    }

    //穩定
    public static void main(String args[]) {


        Library lib = new Library();

        Application app = new Application();

        lib.step1();

        if (app.step2()) {
            lib.step3();
        }

        for (int i = 0; i < 4; i++) {
            app.step4();
        }

        lib.step5();
    }

}
優化程式碼:
//程式庫開發人員
abstract class Library {
    public void run() {//穩定 template method

        step1();
        if (step2()) {//支援變化 ==> 虛擬函式的多型呼叫
            step3();
        }

        for (int i = 0; i < 4; i++) {
            step4();//支援變化 ==> 虛擬函式的多型呼叫
        }

        step5();
    }


    protected void step1() {//穩定
        //...
    }

    protected void step3() {//穩定
        //...
    }

    protected void step5() {//穩定
        //...
    }

    abstract boolean step2();//變化

    abstract void step4();//變化
}
//應用程式開發人員
class Application extends Library {

    @Override
    protected boolean step2() {
        //... 子類重寫實現
        return true;
    }

    @Override
    protected void step4() {
        //... 子類重寫實現
    }

    public static void main(String args[]) {

        Library lib = new Application();
        lib.Run();

    }

}
使用Template模式優化後,將本來要寫在應用程式程式碼中演算法骨架提前新增到程式庫中來,而應用程式開發人員只需要override重寫方法即可。 ◆  要點總結:
        ●  它用最簡潔的機制(虛擬函式的多型性)為很多應用程式框架提供了靈活的擴充套件點,是程式碼複用方面的基本實現結構;         ●  除了可以靈活應對子步驟的變化外,“不要呼叫我,讓我來呼叫你”的反向控制結構是Template的典型應用;         ●  在具體實現方面,被Template呼叫的虛方法可以具有實現,也可以沒有任何實現(抽象方法、純虛方法),但一般推薦將它們設定為protected方法。

2.  Strategy策略模式

◆  動機:         在軟體構建過程中,某種物件使用的演算法可能多種多樣,經常改變,如果將這些演算法都編碼到物件中,將會使物件變得異常複雜;而且有時候支援不使用的演算法也是一種效能負擔。如何在執行時根據需要透明的更改物件的演算法?將演算法與物件本身解耦,從而避免上述問題? 初始程式碼:
public enum TaxBase {
    CN_Tax,
    US_Tax,
    DE_Tax,
    FR_Tax, //更改
};

public class SalesOrder{

    TaxBase tax;

    public void calculateTax(){

        //...

        switch(tax){
            case CN_Tax:
                //CN***********
                break;
            case US_Tax:
                //US***********
                break;
            case De_Tax:
                //DE***********
                break;
            case FR_Tax:  //更改
                //FR***********
                break
        }


        //....
    }

}
上述程式碼中,如果要增加一個選項,需要在兩處進行更改; 優化程式碼:
abstract class TaxStrategy{
    public abstract double Calculate(Context context);
}

public class CNTax extends TaxStrategy{

    @Override
    public double Calculate(Context context){
        //......
    }

}

public class USTax extends TaxStrategy{

    @Override
    public  double Calculate(Context context){
        //******
    }
}

public class DETax extends TaxStrategy{

    @Override
    public  double Calculate(Context context){
        //######
    }
}

//擴充套件
public class FRTax extends TaxStrategy{

    @Override
    public  double Calculate(Context context){
        //######
    }
}



public class SalesOrder{

    TaxStrategy strategy;

    public SalesOrder(TaxStrategy strategy){
        this.strategy=strategy;
    }


    public double CalculateTax(){
        //...
        Context context;

        double val=strategy.Calculate(context);//多型呼叫
        //...

    }

}
        優化後,好處有兩點:1. 只需要擴充套件一個FRtext選項即可,主題演算法是不需要改變的;2. 初始程式碼中,編譯器要編譯所有的程式碼,即使有些case裡的選項是用不到的。優化後,利用抽象類的多型性,只有需要的選項才會被例項化進行編譯,這樣能夠節省CPU的應用空間。 ◆  模式定義:         定義一系列演算法,把它們一個個封裝起來,並且使它們可互相替換。該模式使得演算法可獨立於使用它的客戶程式而變化(擴充套件,子類化)。在上例中,我們用類來封裝每一個演算法,然後建立一個基類的統一的介面。通過介面,當需要哪一個演算法時就呼叫哪個演算法。當需求變更時,我們只需要擴充套件一個子類即可。其中,客戶程式就是SaleOrder()方法,演算法改變,但客戶程式不需要改變。 ◆  要點總結:         ●  Strategy及其子類為元件提供了一系列可重用的演算法,從而可以使得型別在執行時方便的根據需要在各個演算法之間切換;         ●  Strategy模式提供了用條件判斷語句以外的另一種選擇,消除條件判斷語句,就是在解耦和。含有很多條件判斷語句的程式碼通常需要Strategy模式;         ●  如果Strategy物件沒有例項變數,那麼各個上下文可以共享同一個Strategy物件,從而節省物件開銷。

3.  Observer觀察者模式

◆  動機:         在軟體構建過程中,我們需要為某些物件建立一種“通知依賴關係”——一個物件(目標物件)的狀態發生改變,所有的依賴物件(觀察者物件)都將得到通知。如果這樣的依賴關係過於緊密,將使軟體不能很好地抵禦變化。使用面向物件技術,可以將這種依賴關係弱化,並形成一種穩定的依賴關係。從而實現軟體體系結構的鬆耦合。
public class MainActivity extends AppCompatActivity {

    private Button mAppendButton;
    private EditText mEditText;
    private TextView mLabelText;

    private int count=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mAppendButton = (Button) findViewById(R.id.appendButton);
        mEditText = (EditText) findViewById(R.id.contentEdit);
        mLabelText = (TextView) findViewById(R.id.countText);


        //訂閱通知
        mEditText.addTextChangedListener(textWatcher);

        //取消訂閱
        //mEditText.removeTextChangedListener(textWatcher);

        mAppendButton.setOnClickListener(clickListener);


    }


    OnClickListener clickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            String content = mEditText.getText().toString().trim();
            //文字框內容處理
            content = content + Integer.toString(count);
            count++;
            mEditText.setText(content);
            mEditText.setSelection(content.length());//游標置於末尾
        }
    };


    TextWatcher textWatcher = new TextWatcher() {

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            Log.i("BeforeTextChanged:", s.toString() );
        }


        public void onTextChanged(CharSequence s, int start, int before, int count) {

            Log.i("OnTextChanged:", s.toString() );
        }

        public void afterTextChanged(Editable s) {
            String count = Integer.toString(s.length());
            mLabelText.setText(count);
        }
    };

}
        上例中,我們對EditText添加了TextWatcher,檢視原始碼可以看到,這個TextWatcher是被新增到一個TextWatcher陣列中,這裡可以新增多個觀察者。並重寫了TextWatcher的三個方法。當EditText的內容發生改變時,就會通知依賴它的物件(MainActivity)執行相應的方法。上面程式碼中定義一個TextWatcher這一塊,就是一個Observer觀察者物件。需求變更時,我們也只需要改變這一塊程式碼即可。上例中,還有一個觀察者物件,就是Button的OnClickListener物件,它只觀察一個物件,所以沒有觀察者列表,這是Observer的一個弱化版。
◆  模式定義:         定義物件間一種一對多的依賴關係,以便當一個物件(Subject)的狀態發生改變時,所有依賴於它的物件都得到通知並自動更新。 ◆  要點總結:         ●  使用面向物件的抽象,Observer模式使得我們可以獨立地改變目標和觀察者,從而使二者的依賴關係達至鬆耦合;
        ●  目標傳送通知時,無需指定觀察者,通知(可以攜帶通知資訊作為引數)會自動傳播;
        ●  觀察者自己決定是否需要訂閱通知,目標物件(例子中的MAinActivity)對此一無所知;
        ●  Observer模式是基於事件的UI框架中非常常用的設計模式,也是MVC模式的一個重要組成部分;

相關推薦

Java面向物件設計模式——工廠方法模式

工廠方法模式(Factory Method) 工廠方法模式分為三種: 1、普通工廠模式,就是建立一個工廠類,對實現了同一介面的一些類進行例項的建立。首先看下關係圖: 舉例如下:(我們舉一個傳送郵件和簡訊的例子) 首先,建立二者的共同介面: publici

Java面向物件設計模式十三——策略模式strategy

策略模式(strategy) 策略模式定義了一系列演算法,並將每個演算法封裝起來,使他們可以相互替換,且演算法的變化不會影響到使用演算法的客戶。         一種方法是 需要設計一個介面,為

面向物件設計原則——單一職責原則

單一職責原則定義(Single Responsibility Principle,SRP) 一個物件應該只包含 單一的職責,並且該職責被完整地封裝在一個類中。 Every  Object should have  a single responsibility, an

PHP面向物件程式設計設計模式策略模式

(一)什麼是面向物件程式設計   面向物件(OO)的定義是什麼,在面向物件的入門課程C++(或者JAVA)中,封裝資料和方法好像是面向物件最重要的一個特點,當然還有基於繼承實現的多型和過載。其實每一種OOP語言,由於彼此功能上的差異性,這些特點只能適用於某一種

面向物件設計模式

一、設計模式的概念 什麼是好的軟體設計?—— 複用! ◆  首先我們要先理解一個問題,什麼是模式? 每一個模式描述了一個在我們周圍不斷重複發生的問題,以及該問題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重複勞動。  ◆  設計模式:也就是為了使程式碼的可複

可複用面向物件軟體基礎——設計模式之總覽

一、設計模式特點 反覆使用 分類編目 經驗總結 二、設計模式宗旨 程式碼重用 使程式碼易於理解 保證程式碼可靠性 三、設計模式分類(23+2) 建立型(5種) 結構型(7種) 行為型(11種) 其他(2種) (1)建立型模式 工廠

設計模式面向物件的六大原則

買 設計模式 這本書已經快半年了,看著嶄新的書,心裡還有很愧疚的,趁著過年,沒啥開發任務。就把最近零零碎碎的知識總結下。 面向物件的六大原則,一些在平常開發中,跟著老大的風格寫程式碼,無意識中肯定遵守了一些原則,只是意識中知道這樣寫程式碼很有調理。具體為什麼,不太清楚。

設計模式觀察者模式

針對 ray 需求 als bool 模式 null rri 主動 觀察者模式 定義了對象之間的一對多的依賴,這樣一來,當一個對象狀態改變時,他的 多有依賴都會受到通知並自動更新。 本例為一個溫度基站,和三個終端。溫度基站為廣播類WeatherData,三個終端監聽者類分別

android深入之設計模式托付模式

-h listen back != new 聚合 string static data- (一)托付模式簡單介紹 托付模式是主要的設計模式之中的一個。托付。即是讓還有一個對象幫你做事情。 更多的模式,如狀態模式、策略模式、訪問者模式本質上是在更特殊的場合採用了托

多線程設計模式

exceptio 很多 main 定義 網絡協議 name 停止 一個隊列 處理 DelayQueue的使用設計 我們談一下實際的場景吧。我們在開發中,有如下場景a) 關閉空閑連接。服務器中,有很多客戶端的連接,空閑一段時間之後需要關閉之。b) 緩存。緩存中的對象,超過了空

設計模式——命令模式

進行 span request st2 ges 耦合 i++ 設計 ima 1.描述 將一個請求封裝為一個對象,從而使用戶可以用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷操作。 2.用途 在程序設計中,經常涉及道一個對象請求另一個對象調用其方法的情

OOAD-設計模式概述

具體類 設計模式的 頂級 http 引用 pen 屬性 整體 依賴倒轉原則 前言   在我們很多時候設計代碼都是需要用到各種不一樣的設計模式的,接下來著幾篇給大家領略一下設計模式。知道設計模式的作用,以及在代碼的具體體現。很多時候我們看不懂代碼就是因為我們不知道它使用的設

設計模式工廠模式

inside 類和對象 ace square 種類型 創建 實體類 需要 服務器 工廠模式 工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。 在工廠模式中,我們在創建對象時不會

設計模式單例模式

分享 公有 交互 線程 加鎖 解決 操作 編譯 進入 1.單例模式(Singleton):由於某種需要,要保證一個類在程序的生命周期中只有一個實例,並提供一個該實例的全局訪問方法。 2.單例模式(Singleton)結構圖: Singleton類,定義了一個GetInst

設計模式—— 簡單工廠

echart 調用 抽象 簡單工廠模式 客戶端 工廠類 info 工具 crete 簡單工廠 簡介 簡單工廠模式屬於創建型模式,又叫做靜態工廠方法(Static Factory Method)模式,但不屬於23種GOF設計模式之一。簡單工廠模式是一個工廠對象決定創建出哪一種

設計模式建造者模式

單實例 抽象類 原型 sys 數組 組合 cto 簡單 builder GOF論述了23種設計模式,它們有3個分類————創建型模式、結構型模式、行為模式。此篇為創建型模式創建型模式抽象了實例化的過程,它們可以幫助某個系統獨立於如何創建、組合以及表示該系統所包含的對象。當系

Java設計模式

val class 特征 advance rect int bsp 分享 工作 Structural patterns 結構型模式 1.適配器模式(Adaptor) 目的:將某個類/接口轉換為client期望的其他形式。適配器讓類可以協同工作,否則就會因為不兼容的接口而無

Java的設計模式

初始化 關心 主體 編程 開發 私有 獲得 避免 style 什麽是設計模式? 設計模式其實是組織代碼方式的一種經驗,由前人在開發中整理歸納出來。 oo設計原則 在oo設計中應該遵循的幾個原則: 封裝變化。即將需要變化的部分與固定不變的部分隔離開,如抽象類中的抽象方法,要

設計模式

規範 img int 想要 trac esp font 抽象工廠模式 version 我們在學習的路上,肯定是要不斷的學習新的知識,開始進階設計模式! 設計模式的緣由 我想任何一個項目的開發,就是必須先經過設計吧,不然想一出寫一出,到最

設計模式Chain Of Responsibility責任鏈模式(未完成)

設計模式篇章,源於網課的學習,以及個人的整理   在我們接收使用者提交的字元時,常常會使用到過濾,在學習責任鏈模式前,我們是這樣做的 1.定義一個類 public class MsgProcesser { String msg; public MsgProce