開發之路(設計模式一:策略模式)

並非每一個自稱本身是個OO的人,他就必定能運用好OOP。

普通程序員寫的東西比如一把普通鑰匙,一把鑰匙只能開一個門,而高級程序員就會「造」萬能鑰匙。
我之前所理解的「簡單」就是一把鑰匙開一把鎖的模式,僅僅只是着眼於解決如今的問題,而設計模式的「複雜」在於它須要造出具備「通用性」的萬能鑰匙。而我之前寫的代碼就是前者,這個「簡單」不是功能的簡單,而是設計的簡單。簡單的設計意味着缺乏靈活性,代碼很鋼硬,僅僅只是面向過程,一步操做緊挨着下一步。
要使代碼可被反覆使用,請用’設計模式’對你的代碼進行設計.程序員


模擬鴨子程序開始了。
首先來一張類圖,這是鴨子程序原始狀態
圖片描述算法

而此時咱們須要添加一個新功能:鴨子飛功能(吐槽:明明不少鴨子不會飛)
這很簡單,難不倒咱們「有OO思想」的人
圖片描述編程

但這樣的設計運用在下面拓展的程序上會變成什麼呢?
圖片描述設計模式

哇哦,很明顯橡皮鴨子不能飛,而在此設計中使用繼承(extends)就變得不合理了,
可是咱們能夠投機取巧一點,變成以下圖
圖片描述ide

這樣小聰明的方法,恐怕我本身看的都不能直視了....
很明顯對於繼承在這個設計當中很幾個致命的地方
1:各個鴨子子類繼承父類時,使得代碼在多個子類中重複
2:沒有拓展性,對於改變會費勁
3:每每改變一點地方不少地方就都要跟着改變,找出其餘鴨子類中不想要的改變,牽一髮而動全身。學習

設計原則一:找出應用中可能須要變化之處,把它們獨立出來,不要和那些不須要變化的代碼混在一塊兒
注:當每次有新的需求的時候,就會使某方面發生變化,那麼你就能夠肯定,這部分的代碼就須要被抽出來,和其餘穩定的代碼有所區分,這樣使得代碼變化引發的不經意後果變少,系統變得更加富有彈性。
圖片描述測試

設計原則二:針對接口編程,而不是針對實現編程。
注:從如今開始咱們編寫的代碼要富有彈性,讓其運行時能「動態」的改變飛行或者呱呱叫行爲this

進行一點小改變
圖片描述
這裏將飛行和叫的行爲各自「抽象」出來成接口,這兩個行爲被分開成兩個類,這兩個類專門爲提供某行爲的實現提供接口。不一樣與以前設計:行爲來自Duck父類中子類的具體實現,或是繼承某個接口並由子類自行實現而來。這兩種作法都依賴「實現」。而此時子類將使用接口所表明的行爲,因此實際的「實現」不會被綁死在鴨子的子類中。(特定的具體行爲編寫在實現了FlyBehavior和QuackBehavior接口的實現類中)spa

這裏放出具體行爲設計
圖片描述
注:此時飛行和叫的動做(接口)能夠被其餘對象複用,此時這兩個行爲和鴨子類(Duck)無關了,並且日後加入新的行爲也不怕了大量修改代碼了。設計

鴨子父類:

package Entity;

import Interface.FlyBehavior;
import Interface.QuackBehavior;

//鴨子父類
public class Duck {
    // 添加兩個接口變量
    FlyBehavior flyBehavior;// 每隻鴨子都會引用完成FlyBehavior接口的對象
    QuackBehavior quackBehavior;// 每隻鴨子都會引用完成QuackBehavior接口的對象

    public FlyBehavior getFlyBehavior() {
        return flyBehavior;
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public QuackBehavior getQuackBehavior() {
        return quackBehavior;
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public Duck() {
    }

    public void swim() {
        System.out.println("鴨子游泳。。。。。。");
    }

    // 動做
    public void display() {
        System.out.println("每隻鴨子都會動");
    }

    // 這些方法取代fly(),quack()
    // 鴨子對象不親自處理呱呱呱叫行爲,而是委託給quackBehavior引用對象
    public void performQuack() {        
        quackBehavior.quack();
    }

    // 鴨子對象不親自處理飛行爲,而是委託給flyBehavior引用對象
    public void performFly() {
        flyBehavior.fly();
    };

}

飛行和叫動做接口

package Interface;
//飛行接口
public interface FlyBehavior {
    public void fly();
}
package Interface;
//鴨子叫接口
public interface QuackBehavior {
    public void quack();
}

//綠頭鴨和橡皮鴨類

package Entity;

import Implements.FlyWithWings;
import Implements.Quack;
//綠頭鴨子類
public class MallardDuck extends Duck {

    @Override
    public void display() {
        System.out.println("綠頭鴨子");
    }

    /* 當MallardDuck被實例化時,
     * 構造器會把繼承來的quackBehavior,flyBehavior 
     * 實例變量初始化成Quack,FlyWithWings的類型
     * Quack,FlyWithWings分別是接口的實現類
     * */
    public MallardDuck() {
        quackBehavior = new Quack();
        flyBehavior = new FlyWithWings();
    }

}
package Entity;

import Implements.FlyNoWay;
import Implements.Squeak;

public class RubberDuck extends Duck {
//橡皮鴨類
    @Override
    public void display() {
        System.out.println("我是一隻橡皮鴨");
    }

    public RubberDuck() {
        quackBehavior = new Squeak();
        flyBehavior = new FlyNoWay();
    }

}

各個行爲的具體實現類,都實現了接口

package Implements;

import Interface.FlyBehavior;

public class FlyNoWay implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("不會飛");
    }

}
package Implements;

import Interface.FlyBehavior;

public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("鴨子飛起來了。。。。。。");
    }

}
package Implements;

import Interface.QuackBehavior;

public class MuteQuack implements QuackBehavior {

    @Override
    public void quack() {
        System.out.println("不會叫");
    }
}
package Implements;

import Interface.QuackBehavior;

public class Quack implements QuackBehavior {

    @Override
    public void quack() {
        System.out.println("鴨子呱呱呱叫。。。。。。");
    }
}
package Implements;

import Interface.QuackBehavior;

public class Squeak implements QuackBehavior {

    @Override
    public void quack() {
        System.out.println("鴨子吱吱吱叫。。。。。。");
        
    }

}

測試類

package TestMain;

import Entity.Duck;
import Entity.MallardDuck;
import Entity.RubberDuck;

public class TestMain {
    public static void main(String[] args) {
        //這裏使用多態,讓Duck知道咱們要建立一隻綠頭鴨
        Duck d = new MallardDuck();
        //重載方法
        d.display();
        d.performQuack();
        d.performFly();        
        System.out.print("\n");
        
        Duck a=new RubberDuck();
        a.display();
        a.performQuack();
        a.performFly();

    }
}

效果:
圖片描述

設計原則三:多用組合,少用繼承。
注:使用組合創建系統具備很大的彈性,不只可將算法封裝成類,更能夠「動態的改變行爲」,只要組合對象符合正確的接口標準便可。

此時我剛剛寫的例子基於一個策略模式思想寫的。固然你可能會問:「用這個設計模式到底有什麼用呢?這樣功能我也能實現了,幹嗎要搞的那麼複雜?」。對此我不能用專業的思想去回答這樣的疑問,我只能說隨着本身學習的不斷深刻每每不少之前自認爲對的東西,實際上是不正確的。

策略模式要點:
1:良好的OO設計必須具有可複用性、可擴充性、可維護性三個特徵
2:模式不是代碼,而是針對設計問題的通用解決方案。
3:大多數的模式都容許系統局部改變獨立於其餘部分。
4:記着把系統中會改變的部分抽出來封裝
5:模式會讓開發人員之間有共同的語言,並且會讓本身少走不少坑

這裏我想說一點,不少人都以爲設計模式跟算法同樣都是無關緊要的東西,我以爲用設計模式是着眼於將來,能夠提升系統的擴展性,減小重複勞動,雖然有的時候可能會增長工做量,但比起後期無止境的維護,這點反而不算什麼,而設計模式是不會提升系統運行速度的,但我認爲設計模式很是重要,包括帶個人前輩程序員都教導我腦中要有模式概念,固然這個要因人而異。

感謝你看到這裏,策略模式部分結束,本人文筆隨便,如有不足或錯誤之處望給予指點,90度彎腰~很快我會發佈下一個設計模式內容,生命不息,編程不止!

參考書籍:《Head First 設計模式》
相關文章
相關標籤/搜索