設(shè)計模式總結(jié)

15年寫的回顧一下。

1.單例模式

DCL(Double CheckLock)

public class Singleton {
    private static Singleton sInstance = null;

    private Singleton(){}
    
    public static Singleton getInstance(){
        if(mInstance == null){
            synchronized(Singleton.class){
                if(mInstance == null){
                    sInstance = new Singleton();
                }
            }
        }

        return sInstance;
    }
}

靜態(tài)內(nèi)部類

public class Singleton{
    private Singleton(){}

    private static class SingletonHolder{
        public static final Singleton sInstance = new Singleton();
    }

    public static Singleton getInstance(){
        return SingletonHolder.sInstance;
    }
}

優(yōu)點

  1. 在內(nèi)存中只有一個實例,減少內(nèi)存開支,減少系統(tǒng)性能開銷;
  2. 避免對資源的多重占用;
  3. 可以在系統(tǒng)設(shè)置全局的訪問點,優(yōu)化和共享資源訪問。

缺點

  1. 擴展困難;
  2. 如果持有Context,很容易引發(fā)內(nèi)存泄漏,此時最好傳遞個單例對象的 Context 最好是 Application Context。

2.Builder 模式

參照 Android 源碼 AlertDialog.java 經(jīng)典 Builder 模式。

http://afra55.github.io/2016/12/22/normal-dialog/

優(yōu)點

  1. 封裝良好。
  2. 建造者獨立,益于擴展。

缺點

會產(chǎn)生多余的Builder以及Director對象,消耗內(nèi)存。


3.原型模式

即克隆原始的文件獲得副本,對副本進行修改并不會影響原始文件。
需要注意的是:使用 Cloneable 實現(xiàn)拷貝時,并不會執(zhí)行構(gòu)造函數(shù)。

public class WordDocument implements Cloneable {

    private String mText;
    private ArrayList<String> mImages = new ArrayList<>();

    public ArrayList<String> getmImages() {
        return mImages;
    }

    public WordDocument(){
        Log.d("WordDocument", "WordDocument 構(gòu)造函數(shù)");
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            WordDocument document = (WordDocument) super.clone();
            document.mText = this.mText;

            /* 類似于這樣的指向地址的引用,也要采用拷貝形式 */
            document.mImages = (ArrayList<String>) this.mImages.clone();
            return document;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public void addImages(String mImages) {
        this.mImages.add(mImages);
    }

    public String getmText() {
        return mText;
    }

    public void setmText(String mText) {
        this.mText = mText;
    }
}

使用方法:

public void use(){
    WordDocument originDoc = new WordDocument();
    originDoc.setmText("doc");
    originDoc.addImages("1");
    originDoc.addImages("2");
    originDoc.addImages("3");

    /* 進行克隆,并進行修改,原始對象并不會被改變 */
    try {
        WordDocument copyDoc = (WordDocument) originDoc.clone();
        copyDoc.setmText("doc copy");
        copyDoc.addImages("1");
        copyDoc.addImages("2");
        copyDoc.addImages("3");
        copyDoc.addImages("4");
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }

}

優(yōu)點

原型模式是在內(nèi)存中二進制流的拷貝,比直接 new 一個對象性能好很多,特別是在循環(huán)體內(nèi)產(chǎn)生大量對象時。

缺點

直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不執(zhí)行的,在實際開發(fā)當中要注意這個問題。


4.工廠模式

定義一個創(chuàng)建對象的接口,讓子類決定實例化哪個類。

創(chuàng)建抽象類

/**
     * Created by yangshuai in the 16:05 of 2016.01.11 .
     * 抽象類
 */
public abstract class BaseFacory {
    public abstract void start();
}

創(chuàng)建子類

/**
 * Created by yangshuai in the 16:09 of 2016.01.11 .
 * 具體工廠類
 */
public class MyFacory extends BaseFacory {
    @Override
    public void start() {
        Log.d("MyFactory", "start");
    }
}

public class MyFacory2 extends BaseFacory {
    @Override
    public void start() {
        Log.d("MyFactory2", "start");
    }
}

獲取工廠實例反射方法(僅參考)

/**
     * 獲取工廠實例
     * @param tClass
     * @param <T>
     * @return
 */
public static <T extends BaseFacory> T getInstatnce(Class<T> tClass) {
    BaseFacory baseFacory = null;
    try {
        baseFacory = (BaseFacory) Class.forName(tClass.getName()).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    return (T) baseFacory;
}

使用方法

BaseFacory factoryMode = FactoryMode.getInstatnce(MyFacory.class);
    if (factoryMode != null) {
        factoryMode.start();
    }

5.策略模式

定義了一些列算法,并分別封裝,并且互相可以替換。經(jīng)?;赜脕矶鄠€if-else或switch-case。

定義通用接口

/**
     * Created by yangshuai in the 10:56 of 2016.01.29 .
 */
public interface Strategy {
    public int strategy();
}

封裝算法

/**
 * Created by yangshuai in the 11:37 of 2016.01.29 .
 */
public class StrategyOne implements Strategy {
    @Override
    public int strategy() {
        Log.d("StrategyOne", "OneStrategy");
        /* 算法操作 */
        return 1;
    }
}

/**
 * Created by yangshuai in the 11:37 of 2016.01.29 .
 */
public class StrategyTwo implements Strategy {
    @Override
    public int strategy() {
        Log.d("StrategyTwo", "TwoStrategy");
        /* 算法操作 */
        return 2;
    }
}

使用

/**
 * Created by yangshuai in the 11:39 of 2016.01.29 .
 */
public class UseStrategy {

    private Strategy strategy = new StrategyOne();

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public int strategy() {
        return strategy.strategy();
    }
}

優(yōu)點

  1. 結(jié)構(gòu)簡單明了,使用簡單直觀;
  2. 耦合度相對較低,擴展方便;
  3. 操作封裝更徹底,數(shù)據(jù)更安全。

缺點

隨著策略的增加,子類會變得繁多。


6.狀態(tài)模式

如果有大量的 分支 語句(if-else, switch-case)或者 要根據(jù)狀態(tài)的改變而改變行為時,狀態(tài)模式是最佳選擇。舉例如下:

創(chuàng)建狀態(tài)接口

/*
    狀態(tài)接口,有三種模式,睡眠、行走、進食。
*/
public interface State{
    public void sleep();
    public void walk();
    public void eatting();
}

創(chuàng)建行為接口

/*
    動作接口,分別是唱歌、移動、玩游戲。
*/
public interface Action{
    public void sing();
    public void move();
    public void playGame();
}

模擬各種狀態(tài)下的行為執(zhí)行方式

// 睡眠模式下的所有行為的模擬
public class SleepState implements Action{

    @Override
    public void sing(){
        System.out.println("You are sleeping, no sing");
    }

    @Override
    public void move(){
        System.out.println("You are sleeping, no move");
    }

    @Override
    public void playGame(){
        System.out.println("You are sleeping, no playGame");
    }
}

// 行走模式下的所有行為的模擬
public class WalkState implements Action{

    @Override
    public void sing(){
        System.out.println("You can sing");
    }

    @Override
    public void move(){
        System.out.println("You can move");
    }

    @Override
    public void playGame(){
        System.out.println("You can playGame");
    }
}

// 進食模式下的所有行為的模擬
public class EatingState implements Action{

    @Override
    public void sing(){
        System.out.println("You are eatting, no sing");
    }

    @Override
    public void move(){
        System.out.println("You are eatting and you could move");
    }

    @Override
    public void playGame(){
        System.out.println("You are eatting and you could playGame");
    }
}

創(chuàng)建狀態(tài)控制器

/*
    控制器, 用于切換狀態(tài)和執(zhí)行行為
*/
public class StateContorller implements State {
    private Action mState;

    public void setState(Action s){
        mState = s;
    }

    @Override
    public void sleep(){
        setState(new SleepState());
    }

    @Override
    public void walk(){
        setState(new WalkState());
    }

    @Override
    public void eatting(){
        setState(new EatingState());
    }
    
    public void sing(){
        mState.sing();
    }
    public void move(){
        mState.move();
    }
    public void playGame(){
        mState.playGame();
    }
}

使用

在不同的狀態(tài)下,執(zhí)行的行為不同:

    StateContorller contorller = new StateContorller();
    contorller.eatting();
    contorller.move();

    contorller.sleep();
    contorller.sing();

    contorller.walk();
    contorller.playGame();

優(yōu)點

優(yōu)化了繁瑣的狀態(tài)判斷,提高了可擴展性和可維護性。像上面這個例子,使用if-else對比下就顯而易見了。

缺點

增加了類和對象的個數(shù)。


7.責(zé)任鏈模式

當多個對象都可以處理一個請求,而且由請求的某個標志決定哪個對象進行處理時使用。

請求也可以是從服務(wù)端獲取的數(shù)據(jù),根據(jù)某個特性來決定處理的對象.

請求基類

/**
 * Created by yangshuai in the 21:48 of 2016.06.15 .
 */
public abstract class BaseDutyRequest {

    // 請求的對象是未知,千變?nèi)f化的
    private Object mObject;

    public BaseDutyRequest(Object object) {
        mObject = object;
    }

    public Object getRequestObject() {
        return mObject;
    }

    // 這里由 一個 int 型的值來標志特性
    public abstract int getDutyLevel();

}

執(zhí)行職責(zé)的基類

/**
 * Created by yangshuai in the 21:43 of 2016.06.15 .
 */
public abstract class BaseDuty {
    // 存儲下一個節(jié)點,最后一個節(jié)點的下個節(jié)點是null
    private BaseDuty nextOne = null;

    public final void setNextOne(BaseDuty baseDuty) {
        nextOne = baseDuty;
    }

    public final BaseDuty getNextOne() {
        return nextOne;
    }
    
    // 獲取請求,根據(jù)請求的特性判斷由誰來處理
    public final void setDutyRequest(BaseDutyRequest request) {
        if (request.getDutyLevel() == getDutyLevel()) {
            doDuty(request);
        } else if (getNextOne() != null) {
            getNextOne().setDutyRequest(request);
        } else {
            beyondTheResponsibilityLevel(request);
        }
    }

    // 執(zhí)行職責(zé)能夠處理的特性,與請求的特性進行對比
    protected abstract int getDutyLevel();

    // 處理請求
    protected abstract void doDuty(BaseDutyRequest request);

    // 在最后一個節(jié)點使用,千萬不要掉到死循環(huán)的bug中
    protected void beyondTheResponsibilityLevel(BaseDutyRequest request) {
        // you can do someting or not;
    }
}

請求舉例

/**
 * Created by yangshuai in the 22:02 of 2016.06.15 .
 */
public class DutyRequestOne extends BaseDutyRequest {
    public DutyRequestOne(Object object) {
        super(object);
    }

    @Override
    public int getDutyLevel() {
        return 0;
    }
}

/**
 * Created by yangshuai in the 22:02 of 2016.06.15 .
 */
public class DutyRequestTwo extends BaseDutyRequest {

    public DutyRequestTwo(Object object) {
        super(object);
    }

    @Override
    public int getDutyLevel() {
        return 0;
    }
}

執(zhí)行職責(zé)舉例

/**
 * Created by yangshuai in the 22:00 of 2016.06.15 .
 */
public class DutyOne extends BaseDuty {
    @Override
    protected int getDutyLevel() {
        return 0;
    }

    @Override
    protected void doDuty(BaseDutyRequest request) {
        // do what you wan't to do;
        request.getRequestObject();
    }
}

/**
 * Created by yangshuai in the 22:01 of 2016.06.15 .
 */
public class DutyTwo extends BaseDuty {
    @Override
    protected int getDutyLevel() {
        return 1;
    }

    @Override
    protected void doDuty(BaseDutyRequest request) {
        // do what you wan't to do;
        request.getRequestObject();
    }
}

使用方法

/**
 * Created by yangshuai in the 22:03 of 2016.06.15 .
 */
public class DutyMode {
    public static void main(String[] args) {

        // 執(zhí)行對象
        DutyOne dutyOne = new DutyOne();
        DutyTwo dutyTwo = new DutyTwo();

        dutyOne.setNextOne(dutyTwo);

        // 請求對象,請求可能是從服務(wù)器獲取的數(shù)據(jù)
        DutyRequestOne dutyRequestOne = new DutyRequestOne("one");
        DutyRequestTwo dutyRequestTwo = new DutyRequestTwo("two");

        // 每次都從第一個節(jié)點進入
        dutyOne.setDutyRequest(dutyRequestOne);
        dutyOne.setDutyRequest(dutyRequestTwo);
    }
}

優(yōu)點

請求和處理解耦,代碼更靈活。

缺點

當處理太多,遍歷的方式會降低性能。


8.命令模式

把執(zhí)行命令分離,記錄執(zhí)行順序。

創(chuàng)建具體執(zhí)行類(命令接收者)

/**
 * Created by yangshuai in the 20:52 of 2016.06.20 .
 * 在電腦上操作,有多種命令,比如 復(fù)制文件,移動文件,新建文件等。
 * Compter類用于實現(xiàn)具體方法。接收各種命令來執(zhí)行方法,即接收者。
 */
public class Computer {

    public void doCopy(String from, String to) {

    }

    public void doMove(String from, String to) {

    }

    public void doNewDefaultFile() {

    }
}

創(chuàng)建命令接口

/**
 * Created by yangshuai in the 20:48 of 2016.06.20 .
 * Command 接口,定義通用執(zhí)行方法,不止一個,可能有多個執(zhí)行.
 */
public interface Command {
    public void execute();
    public void execute(String from, String to);
}

創(chuàng)建命令實現(xiàn)類

/**
 * Created by yangshuai in the 20:58 of 2016.06.20 .
 * Copy 的命令實現(xiàn)類。
 */
public class DoCopyCommand implements Command {

    private final Computer mComputer;

    public DoCopyCommand(Computer computer) {
        mComputer = computer;
    }

    @Override
    public void execute() {
        throw new IllegalArgumentException("DoCopyCommand need from and to");
    }

    @Override
    public void execute(String from, String to) {
        mComputer.doCopy(from, to);
    }
}

/**
 * Created by yangshuai in the 20:58 of 2016.06.20 .
 * Move 的命令實現(xiàn)類。
 */
public class DoMoveCommand implements Command {

    private final Computer mComputer;

    public DoMoveCommand(Computer computer) {
        mComputer = computer;
    }

    @Override
    public void execute() {
        throw new IllegalArgumentException("DoMoveCommand need from and to");
    }

    @Override
    public void execute(String from, String to) {
        mComputer.doMove(from, to);
    }
}

/**
 * Created by yangshuai in the 20:58 of 2016.06.20 .
 * New file 的命令實現(xiàn)類。
 */
public class DoNewDefaultCommand implements Command {

    private final Computer mComputer;

    public DoNewDefaultCommand(Computer computer) {
        mComputer = computer;
    }

    @Override
    public void execute() {
        mComputer.doNewDefaultFile();
    }

    @Override
    public void execute(String from, String to) {
        throw new IllegalArgumentException("DoNewDefaultCommand do not need arguments");
    }
}

創(chuàng)建請求類

/**
 * Created by yangshuai in the 21:06 of 2016.06.20 .
 * 這些命令都能用鼠標來在電腦上操作實現(xiàn)。
 * Mouse 用于發(fā)起命令,充當請求者模式。并可以記錄執(zhí)行命令,方便取消等操作。
 */
public class Mouse {
    private Command doCopyCommand;
    private Command doMoveCommand;
    private Command doNewDefaultCommand;

    private List<Command> doCommands = new ArrayList<>();

    public List<Command> getDoCommands() {
        return doCommands;
    }

    public void setDoCopyCommand(Command doCopyCommand) {
        this.doCopyCommand = doCopyCommand;
    }

    public void setDoMoveCommand(Command doMoveCommand) {
        this.doMoveCommand = doMoveCommand;
    }

    public void setDoNewDefaultCommand(Command doNewDefaultCommand) {
        this.doNewDefaultCommand = doNewDefaultCommand;
    }

    public void doCopy(String from, String to) {
        if (doCopyCommand == null) {
            return;
        }
        doCopyCommand.execute(from, to);
        doCommands.add(doCopyCommand);
    }

    public void doMove(String from, String to) {
        if (doMoveCommand == null) {
            return;
        }
        doMoveCommand.execute(from, to);
        doCommands.add(doMoveCommand);
    }

    public void doNewDefaultFile() {
        if (doNewDefaultCommand == null) {
            return;
        }
        doNewDefaultCommand.execute();
        doCommands.add(doNewDefaultCommand);
    }
}

執(zhí)行

/**
 * Created by yangshuai in the 21:19 of 2016.06.20 .
 * 由人來決定怎么去執(zhí)行
 */
public class People {
    public static void main(String []args) {

        // 要創(chuàng)建一個電腦,即命令接收者來實現(xiàn)命令
        Computer computer = new Computer();

        // 創(chuàng)建命令
        Command doCopyCommand = new DoCopyCommand(computer);
        Command doMoveCommand = new DoMoveCommand(computer);
        Command doNewDefaultCommand = new DoNewDefaultCommand(computer);

        // 創(chuàng)建鼠標,用來發(fā)起命令請求
        Mouse mouse = new Mouse();

        // 準備命令
        mouse.setDoCopyCommand(doCopyCommand);
        mouse.setDoMoveCommand(doMoveCommand);
        mouse.setDoNewDefaultCommand(doNewDefaultCommand);

        // 執(zhí)行命令
        mouse.doNewDefaultFile();
        mouse.doMove("from", "to");
        mouse.doCopy("from", "to");
    }
}

優(yōu)點

增加了擴展性,分離了請求者和接收者,弱化耦合。我覺得做大的優(yōu)點是可以記錄命令的執(zhí)行順序,進而實現(xiàn)撤銷操作。

缺點

這種寫法極大的增加了代碼量,創(chuàng)建了大量的類。如果,不需要記錄執(zhí)行命令,我覺得還是別用的好。


9. 觀察者模式

多個對象來監(jiān)聽一個行為,這個時候用觀察者模式比較好。
下面舉例,多個吃貨接收到食堂發(fā)來的食品菜單。

創(chuàng)建觀察者

import com.afra55.baseclient.util.Log;

import java.util.Observable;
import java.util.Observer;

/**
 * Created by yangshuai in the 20:37 of 2016.06.21 .
 * 吃貨的手機會接收到食堂發(fā)來的最新菜單,在 update 方法中接收信息
 */
public class Eater implements Observer {

    private String phone;

    public Eater(String phone) {
        this.phone = phone;
    }

    @Override
    public void update(Observable observable, Object data) {
        Log.d("Eater", "Today's food menu: " + data +" has sent to " + phone);
    }
}

創(chuàng)建被觀察者

import java.util.Observable;

/**
 * Created by yangshuai in the 20:47 of 2016.06.21 .
 * 食堂管理員收到新的菜單信息,發(fā)送給所有已經(jīng)注冊過的吃貨
 */
public class CanteenManager extends Observable {


    public void sendNewFoodMenu(String menu) {
        setChanged();
        notifyObservers(menu);
    }
}

關(guān)聯(lián)觀察者與被觀察者

/**
 * Created by yangshuai in the 20:49 of 2016.06.21 .
 */
public class FoodMaker {

    public static void main(String[] args) {

        // 創(chuàng)建食堂管理員
        CanteenManager canteenManager = new CanteenManager();

        // 創(chuàng)建吃貨
        Eater eater = new Eater("111111");
        Eater eater2 = new Eater("222222");
        Eater eater3 = new Eater("333333");

        // 注冊吃貨
        canteenManager.addObserver(eater);
        canteenManager.addObserver(eater2);
        canteenManager.addObserver(eater3);

        // 更新食物菜單,每個注冊了的吃貨都會 在 update 方法里接收到新的信息
        canteenManager.sendNewFoodMenu("米飯");
        canteenManager.sendNewFoodMenu("餃子");
        canteenManager.sendNewFoodMenu("嘛事");

    }
}

優(yōu)點

被觀察者有信息變動觀察者都會收到信息,便于功能變更,業(yè)務(wù)擴展,同時增強了靈活性。

缺點

觀察者太多會造成性能降低,不便于問題排查。


10.備忘錄模式

備忘錄模式很簡單,在某個時刻保存某個對象的狀態(tài)或者數(shù)據(jù),或者對象的狀態(tài)不想被外界直接獲取到而是利用中間代理存儲狀態(tài)并暴露給外界,這個時候備忘錄模式是很好的選擇。
下面以看書為例,介紹備忘錄模式:

需要存儲對象的類

/**
 * Created by yangshuai in the 22:40 of 2016.06.22 .
 * 書本每次閱讀頁數(shù)都會加1,在不閱讀的情況下要記錄當前閱讀的頁數(shù),以便下次接著閱讀
 */
public class Book {

    private int page;

    /**
     * 每次閱讀頁數(shù)都會加1
     */
    public void read() {
        page++;
    }

    /**
     * 不閱讀,合起書本的時候頁數(shù)會變?yōu)?
     */
    public void leave() {
        page = 0;
    }

    /**
     * 創(chuàng)建書簽,存儲當前閱讀的頁數(shù)
     * @return
     */
    public Bookmark createBookmark() {
        Bookmark bookmark = new Bookmark();
        bookmark.setPage(page);
        return bookmark;
    }

    /**
     * 繼續(xù)閱讀,翻到書簽的那一頁
     * @param bookmark
     */
    public void backToRead(Bookmark bookmark) {
        page = bookmark.getPage();
    }

}

創(chuàng)建備忘錄類

/**
 * Created by yangshuai in the 22:43 of 2016.06.22 .
 * 書簽,備忘錄該存儲的數(shù)據(jù)類
 */
public class Bookmark {

    private int page = 0;

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }
}

創(chuàng)建備忘錄管理員

/**
 * Created by yangshuai in the 22:51 of 2016.06.22 .
 * 管理書簽,用來存儲和獲取備忘錄,如果外界想獲取狀態(tài),只能通過中間管理員獲取
 */
public class People {
    private Bookmark bookmark;

    public Bookmark getBookmark() {
        return bookmark;
    }

    public void setBookmark(Bookmark bookmark) {
        this.bookmark = bookmark;
    }
}

使用

/**
 * Created by yangshuai in the 22:54 of 2016.06.22 .
 */
public class World {
    public static void main(String[] args) {
        // 創(chuàng)建一本書
        Book book = new Book();
        book.read();

        // 創(chuàng)建一個管理者,管理備忘錄
        People people = new People();

        // 管理者存儲書簽
        people.setBookmark(book.createBookmark());

        // 不再閱讀書,合起書
        book.leave();

        // 一段時間后繼續(xù)閱讀未讀完的書,接著上次的頁數(shù)
        book.backToRead(people.getBookmark());
        book.read();
    }
}

優(yōu)點

  1. 為程序提供了對象的狀態(tài)恢復(fù)機制;
  2. 對數(shù)據(jù)進行了封裝,使用者不必關(guān)心如何實現(xiàn)保存細節(jié),只用存儲或者獲取數(shù)據(jù)。

缺點

設(shè)計模式的通病,類的泛濫,而且存取狀態(tài)會占用資源。


11.迭代器模式

遍歷對象的時候使用,在遍歷多種容器的對象的時候使用最佳。

下面以遍歷男子高校和女子高校的信息舉例:

創(chuàng)建對象

/**
 * Created by yangshuai in the 21:15 of 2016.06.30 .
 * 元素對象,這里以人的信息舉例
 */
public class People {

    private String name;
    private int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

創(chuàng)建迭代器接口

/**
 * Created by yangshuai in the 21:12 of 2016.06.30 .
 * 迭代器接口
 */
public interface Iterator {

    /**
     * 判斷是否還有下一個元素
     * @return
     */
    boolean hasNext();

    /**
     * 返回當前位置的元素,并將位置參數(shù)加 1
     * @return
     */
    Object next();
}

創(chuàng)建迭代器

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yangshuai in the 21:14 of 2016.06.30 .
 * 男子高校人員信息迭代器
 */
public class ManIterator implements Iterator {

    private List<People> list = new ArrayList<>();
    private int index = 0;

    public ManIterator(List<People> list) {
        list.addAll(list);
    }

    @Override
    public boolean hasNext() {
        return index < list.size() && list.get(index) != null;
    }

    @Override
    public Object next() {
        return list.get(index++);
    }
}

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yangshuai in the 21:24 of 2016.06.30 .
 * 女子高校人員信息迭代器
 */
public class WomanIterator implements Iterator {

    private List<People> list = new ArrayList<>();
    private int index = 0;

    public WomanIterator(List<People> list) {
        this.list.addAll(list);
    }

    @Override
    public boolean hasNext() {
        return index < list.size() && list.get(index) != null;
    }

    @Override
    public Object next() {
        return list.get(index++);
    }
}

創(chuàng)建容器接口

/**
 * Created by yangshuai in the 21:29 of 2016.06.30 .
 * 定義一個通用接口,用來返回容器,或者也可以進行添加刪除人員, 也可以更新人員信息(略)。
 */
public interface School {

    void add(People people);

    void Remove(People people);

    /**
     * 只有在使用的時候在創(chuàng)建容器對象
     * @return
     */
    Iterator iterator();
}

創(chuàng)建容器

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yangshuai in the 21:27 of 2016.06.30 .
 */
public class ManSchool implements School {

    private List<People> list;

    public ManSchool() {
        list = new ArrayList<>();
    }

    @Override
    public void add(People people) {
        list.add(people);
    }

    @Override
    public void Remove(People people) {
        if (list.contains(people)) {
            list.remove(people);
        }
    }

    @Override
    public Iterator iterator() {
        return new ManIterator(list);
    }
}

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yangshuai in the 21:27 of 2016.06.30 .
 */
public class WomanSchool implements School {

    private List<People> list;

    public WomanSchool() {
        list = new ArrayList<>();
    }

    @Override
    public void add(People people) {
        list.add(people);
    }

    @Override
    public void Remove(People people) {
        if (list.contains(people)) {
            list.remove(people);
        }
    }

    @Override
    public Iterator iterator() {
        return new WomanIterator(list);
    }
}

調(diào)用方法

/**
 * Created by yangshuai in the 21:34 of 2016.06.30 .
 * 遍歷男子高校和女子高校的信息就可以使用一種方法。
 */
public class Use {
    public static void main(String []args) {
        WomanSchool womanSchool = new WomanSchool();
        womanSchool.add(new People("a", 11));
        womanSchool.add(new People("b", 11));
        womanSchool.add(new People("c", 11));
        showSchoolPeopleInfo(womanSchool.iterator());


        ManSchool manSchool = new ManSchool();
        manSchool.add(new People("d", 11));
        manSchool.add(new People("e", 11));
        manSchool.add(new People("f", 11));
        showSchoolPeopleInfo(womanSchool.iterator());


    }

    public static void showSchoolPeopleInfo(Iterator iterator) {
        if (iterator.hasNext()) {
            iterator.next().toString();
        }
    }
}

優(yōu)點

分離遍歷算法和容器。

缺點

增加了類文件。


12.模板方法模式

抽取公有方法到基類中,讓其他類都繼承這個基類,例如 BaseActiviy,你懂的,這里就不再舉例。

優(yōu)點

  1. 封裝了公用的代碼,易于維護更新;
  2. 可以自由重寫擴展公用方法,保留不變代碼。

缺點

代碼閱讀困難。那不怪我嘍,你要看不懂。


13.訪問者模式

一個對象有有多個互不關(guān)聯(lián)的方法,這些方法又被不同的對象調(diào)用,這個時候使用訪問者模式比較好。

下面以游客逛公園舉例,公園有熊貓和跳跳虎,年輕人與熊貓玩給跳跳虎喂食,老年人看看介紹就可以了:

創(chuàng)建訪問者

訪問者要對不同的元素有不同的訪問方式,給跳跳虎喂食,與熊貓玩耍,所以要區(qū)分開來:

/**
 * Created by yangshuai in the 21:09 of 2016.07.04 .
 * 訪問者接口,訪問每個動物。
 */
public interface Visitor {
    void visit(Tigger tigger);

    void visit(Panda panda);
}

創(chuàng)建元素接口或抽象類,定義被訪問對象

被訪問者要實現(xiàn) accept 接口,用來接收訪問者的訪問:

/**
 * Created by yangshuai in the 21:00 of 2016.07.04 .
 * 動物基類,有兩個屬性 名字和種類
 */
public abstract class Anim {
    public String name;
    public String variety;

    public Anim(String name, String variety) {
        this.name = name;
        this.variety = variety;
    }

    /**
     * 接受訪問者的訪問
     * @param visitor
     */
    protected abstract void accept(Visitor visitor);
}

創(chuàng)建具體的被訪問者

/**
 * Created by yangshuai in the 21:11 of 2016.07.04 .
 * 熊貓
 */
public class Panda extends Anim {

    public Panda(String name) {
        super(name, "吃竹子的");
    }

    @Override
    protected void accept(Visitor visitor) {
        visitor.visit(this);
    }

    /**
     * 熊貓玩耍
     * @param player
     * @return
     */
    public String playWith(String player) {
        Log.d(name, "和" + player + "玩的超級開心吶");
        return "玩的開心";
    }
}

/**
 * Created by yangshuai in the 21:10 of 2016.07.04 .
 * 跳跳虎
 */
public class Tigger extends Anim{
    public Tigger(String name) {
        super(name, "吃肉的");
    }

    @Override
    protected void accept(Visitor visitor) {
        visitor.visit(this);
    }

    /**
     * 老虎進食
     * @param food
     * @return
     */
    public String eat(String food) {
        Log.d(name, "eat :" + food);
        return "吃的開心";
    }
}

創(chuàng)建被訪問元素的集合

/**
 * Created by yangshuai in the 21:25 of 2016.07.04 .
 * 動物園,有三個熊貓,兩個跳跳虎
 */
public class Zoo {
    private List<Anim> list = new LinkedList<>();

    public Zoo() {
        list.add(new Panda("小花"));
        list.add(new Panda("小1"));
        list.add(new Panda("小a"));
        list.add(new Tigger("小妞"));
        list.add(new Tigger("小BB"));
    }

    /**
     * 開門營業(yè),訪問者訪問每個動物
     * @param visitor
     */
    public void openDoor(Visitor visitor) {
        for (Anim anim : list) {
            anim.accept(visitor);
        }
    }
}

創(chuàng)建具體的訪問者

/**
 * Created by yangshuai in the 21:20 of 2016.07.04 .
 * 老人只要知道動物的種類就可以了
 */
public class OldMan implements Visitor {

    @Override
    public void visit(Tigger tigger) {
        Log.d("OldMan", tigger.variety);
    }

    @Override
    public void visit(Panda panda) {
        Log.d("OldMan", panda.variety);
    }
}

/**
 * Created by yangshuai in the 21:20 of 2016.07.04 .
 * 年輕人不僅要知道動物的名字還要和動物互動
 */
public class YoungMan implements Visitor {
    @Override
    public void visit(Tigger tigger) {
        Log.d("YoungMan", tigger.name + ":" + tigger.eat("food"));
    }

    @Override
    public void visit(Panda panda) {
        Log.d("YoungMan", panda.name + ":" + panda.playWith("Afra"));
    }
}

使用方法

/**
 * Created by yangshuai in the 21:28 of 2016.07.04 .
 */
public class IsTimeToPlay {
    public static void main(String[] args) {

        // 創(chuàng)建動物園
        Zoo zoo = new Zoo();

        // 創(chuàng)建老年訪問者
        OldMan oldMan = new OldMan();
        zoo.openDoor(oldMan);

        // 創(chuàng)建青年訪問者
        YoungMan youngMan = new YoungMan();
        zoo.openDoor(youngMan);

    }
}

優(yōu)點

上面的情景要是使用 if-else 的話,難以擴展和維護,甚至類型多的情況下會很復(fù)雜:

if 老年人
   讀取動物介紹
else if 年輕人
    if 跳跳虎
         動物喂食
    if 熊貓
         動物玩
  1. 訪問者模式另各個角色分離;
  2. 擴展性良好,更靈活;
  3. 數(shù)據(jù)和操作解耦;

缺點

1.被訪問者修改了后,操作修改變更大;
2.為了對訪問的對象有不同的操作,而依賴了具體的類;


14.中間人模式

當多個對象的操作互相依賴,互相影響時,中間人模式是個很好的選擇。

接下來以拍電影舉例,導(dǎo)演喊開始,中間人跑去跟演員說導(dǎo)演喊開始啦,然后演員開始表演,演員突然笑場,要中間人跑去給導(dǎo)演說,演員笑場了,然后導(dǎo)演重新喊開始:

定義中間人抽象類,也可以是接口

/**
 * Created by yangshuai in the 22:07 of 2016.07.05 .
 * 中間人,跑腿的,每個人的狀態(tài)更新后都要去通知相關(guān)的人。
 */
public abstract class Mediator {

    public abstract void updataState(People people);
}

定義互相影響的對象的抽象基類,也可以是接口

/**
 * Created by yangshuai in the 22:07 of 2016.07.05 .
 * 人的抽象類,可以是接口
 */
public abstract class People {
    protected Mediator mediator;

    public People(Mediator mediator) {
        this.mediator = mediator;
    }
}

創(chuàng)建具體的互相影響的對象

/**
 * Created by yangshuai in the 22:13 of 2016.07.05 .
 * 導(dǎo)演,用于喊 開始,然后演員開始演戲
 */
public class Director extends People {
    public Director(Mediator mediator) {
        super(mediator);
    }

    public void action() {
        mediator.updataState(this);
    }
}

/**
 * Created by yangshuai in the 22:15 of 2016.07.05 .
 * 演員,在導(dǎo)演喊開始后開始演戲,中間笑場了導(dǎo)演要重新喊開始。
 */
public class Player extends People {
    public Player(Mediator mediator) {
        super(mediator);
    }

    public void laughAload() {
        mediator.updataState(this);
    }

    public void play() {
        // 開始表演
    }
}

創(chuàng)建具體的中間人

/**
 * Created by yangshuai in the 22:17 of 2016.07.05 .
 * 跑腿的就是中間人,負責(zé)通知導(dǎo)演或者演員狀態(tài)更新。
 */
public class Footwork extends Mediator {

    private Player player;
    private Director director;

    public void setPlayer(Player player) {
        this.player = player;
    }

    public void setDirector(Director director) {
        this.director = director;
    }

    @Override
    public void updataState(People people) {
        if (people instanceof Director) { // 導(dǎo)演喊開始了,這里簡化了判斷
            if (player != null) {
                player.play();
            }
        } else if (people instanceof Player) {  // 演員笑場了,這里簡化了判斷
            if (director != null) {
                director.action();
            }
        }
    }
}

使用

/**
 * Created by yangshuai in the 22:22 of 2016.07.05 .
 */
public class Room {
    public static void main(String args[]) {

        // 創(chuàng)建中間人,即跑腿的
        Footwork mediator = new Footwork();

        // 創(chuàng)建導(dǎo)演
        Director director = new Director(mediator);
        mediator.setDirector(director);

        // 創(chuàng)建演員
        Player player = new Player(mediator);
        mediator.setPlayer(player);

        // 導(dǎo)演喊開始了,然后中間人通知演員開始演戲
        director.action();

        // 演員笑場了,然后中間人通知導(dǎo)演重新喊開始
        player.laughAload();
    }
}

優(yōu)點

解耦復(fù)雜的依賴,清晰邏輯,降低復(fù)雜度,提高擴展性。

缺點

要是互相依賴的操作量少,中間人模式可能會導(dǎo)致代碼的邏輯結(jié)構(gòu)更加復(fù)雜化。


15.代理模式

當沒法去訪問一個對象時可以通過代理模式間接訪問。代理對象和被代理對象要有相同的接口。

以下以中午帶飯為例進行舉例:

創(chuàng)建代理接口(代理人和被代理人都要實現(xiàn))

/**
 * Created by Afra55 on 2016.07.09 .
 * 中午吃飯接口, 走路去飯店,購買自己喜歡的食物
 */
public interface IEat {

    /**
     * 走路去飯店
     */
    void walk();

    /**
     * 選擇食物
     */
    void choose();

    /**
     * 購買
     */
    void buy();

}

創(chuàng)建懶人(被代理人)

/**
 * Created by Afra55 on 2016.07.09 .
 * 具體的中午吃飯的人
 */
public class Layzer implements IEat {

    @Override
    public void walk() {
        System.out.println("走路去飯店");
    }

    @Override
    public void choose() {
        System.out.println("選擇食物");
    }

    @Override
    public void buy() {
        System.out.println("掏錢買");
    }
}

靜態(tài)代理

創(chuàng)建代理人

/**
 * Created by Afra55 on 2016.07.09 .
 * 懶人懶得出去買飯,交給 Greater 去買,Greater 就是代理人
 */
public class Greater implements IEat {

    private final IEat eater;

    public Greater(IEat iEat) {
        this.eater = iEat;
    }

    @Override
    public void walk() {
        eater.walk();
    }

    @Override
    public void choose() {
        eater.choose();
    }

    @Override
    public void buy() {
        eater.buy();
    }
}

使用方法

/**
 * Created by Afra55 on 2016.07.09 .
 * 被代理人 通過 代理人 來完成一些列事情
 */
public class Main {
    public static void main(String []args) {

        // 被代理對象
        IEat layzer = new Layzer();

        // 代理人
        IEat greater = new Greater(layzer);

        greater.walk();
        greater.choose();
        greater.buy();
    }
}

動態(tài)代理

動態(tài)代理即通過反射動態(tài)生成代理對象,在運行階段來決定被代理對象而不是編碼階段。在這里使用java提供的動態(tài)代理接口 InvocationHandler。

創(chuàng)建動態(tài)代理實現(xiàn)類

/**
 * Created by Afra55 on 2016.07.09 .
 * 動態(tài)代理
 */
public class DynamicProxy implements InvocationHandler {

    private final Object object;

    public DynamicProxy(Object o) {
        this.object = o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(object, args);
    }
}

使用

/**
 * Created by Afra55 on 2016.07.09 .
 * 被代理人 通過 代理人 來完成一些列事情
 */
public class Main {
    public static void main(String []args) {

        // 被代理對象
        IEat layzer = new Layzer();

        // 獲取 classloader
        ClassLoader classLoader = Layzer.class.getClassLoader();

        // 創(chuàng)建動態(tài)代理
        DynamicProxy dynamicProxy = new DynamicProxy(layzer);

        // 動態(tài)創(chuàng)建代理人,完全與被代理對象解耦,不必關(guān)心去代理誰,也不必創(chuàng)建代理人類
        IEat greater = (IEat) Proxy.newProxyInstance(classLoader, new Class[]{IEat.class}, dynamicProxy);

        greater.walk();
        greater.choose();
        greater.buy();

    }
}

優(yōu)點

叼。

缺點

叼。


16.組合模式

如果一個整體能獨立出一部分模塊或功能時使用。例如,團隊和個人。
下面以社會舉例,社會由群眾組成,群眾由團隊組成,團隊由個人組成。

安全的組合模式

創(chuàng)建抽象基類

/**
 * Created by Afra55 on 2016.07.12 .
 * 抽象類,用于表示整個社會
 */
public abstract class Society {

    protected String name;

    public Society(String name) {
        this.name = name;
    }

    public abstract void doSomething();
}

創(chuàng)建群眾

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Afra55 on 2016.07.12 .
 * 社會由群體組成,群體是社會的具體實現(xiàn).
 * 群體又由各個團隊組成.
 */
public class Mass extends Society {

    /**
     * 存儲各個團隊的容器
     */
    private List<Society> societyList = new ArrayList<>();

    public Mass(String name) {
        super(name);
    }

    /**
     * 添加團隊
     * @param society 團隊
     */
    public void addTeam(Society society) {
        societyList.add(society);
    }

    /**
     * 移除團隊
     * @param society 團隊
     */
    public void removeTeam(Society society) {
        if (societyList.contains(society)) {
            societyList.remove(society);
        }
    }

    /**
     * 獲取團隊數(shù)量
     * @return 團隊的數(shù)量
     */
    public int getTeamCount() {
        return societyList.size();
    }

    /**
     * 獲取團隊
     * @param index 團隊索引
     * @return
     */
    public Society getTeam(int index) {
        if (index < getTeamCount()) {
            return societyList.get(index);
        } else {
            throw new IndexOutOfBoundsException("這個團隊不存在");
        }
    }

    @Override
    public void doSomething() {
        System.out.println(name + "群眾是偉大的");
        for (int i = 0 ; i< getTeamCount(); i++) {
            getTeam(i).doSomething();
        }
    }
}

創(chuàng)建團隊

/**
 * Created by Afra55 on 2016.07.12 .
 * 個人組成了群眾,個人又有個人組成
 */
public class Team extends Society {

    /**
     * 存儲個人的容器
     */
    private List<Society> societyList = new ArrayList<>();
    
    public Team(String name) {
        super(name);
    }

    /**
     * 添加個人
     * @param society 個人
     */
    public void addPeople(Society society) {
        societyList.add(society);
    }

    /**
     * 移除個人
     * @param society 個人
     */
    public void removePeople(Society society) {
        if (societyList.contains(society)) {
            societyList.remove(society);
        }
    }

    /**
     * 獲取個人數(shù)量
     * @return 個人的數(shù)量
     */
    public int getPeopleCount() {
        return societyList.size();
    }

    /**
     * 獲取個人
     * @param index 個人索引
     * @return
     */
    public Society getPeople(int index) {
        if (index < getPeopleCount()) {
            return societyList.get(index);
        } else {
            throw new IndexOutOfBoundsException("這個人不存在");
        }
    }

    @Override
    public void doSomething() {
        System.out.println(name + "團隊是偉大的");
        for (int i = 0 ; i< getPeopleCount(); i++) {
            getPeople(i).doSomething();
        }
    }
}

創(chuàng)建個人

/**
 * Created by Afra55 on 2016.07.12 .
 * 個人組成了團隊,是整個社會的記事
 */
public class People extends Society {

    public People(String name) {
        super(name);
    }

    @Override
    public void doSomething() {
        System.out.println(name + "是偉大的");
    }
}

使用

public class Main {
    public static void main(String []args) {

        // 創(chuàng)建個人
        People afra55 = new People("Afra55");
        People victor = new People("Victor");
        People aaa = new People("AAA啊哈");

        // 創(chuàng)建 java tema
        Team javaTeam = new Team("Java");
        javaTeam.addPeople(afra55);

        // 創(chuàng)建 android team
        Team androidTeam = new Team("Andrid");
        androidTeam.addPeople(victor);
        androidTeam.addPeople(aaa);

        // 創(chuàng)建群眾
        Mass mass = new Mass("西安");
        mass.addTeam(javaTeam);
        mass.addTeam(androidTeam);

        mass.doSomething();
    }
}

輸出:

西安群眾是偉大的
Java團隊是偉大的
Afra55是偉大的
Andrid團隊是偉大的
Victor是偉大的
AAA啊哈是偉大的

透明的組合模式

上述的例子中,不同的成員是有著不同的結(jié)構(gòu),在透明的組合模式中,他們都有著相同的結(jié)構(gòu),因而一些操作要放到內(nèi)部進行判斷。對于面向接口的編程,這個方法優(yōu)先考慮。

創(chuàng)建抽象基類

/**
 * Created by Afra55 on 2016.07.12 .
 * 抽象類,用于表示整個社會
 */
public abstract class Society {

    protected String name;

    public Society(String name) {
        this.name = name;
    }

    /**
     * 添加子模塊
     * @param society
     */
    public abstract void addSubSociety(Society society);

    /**
     * 移除子模塊
     * @param society
     */
    public abstract void removeSubSociety(Society society);

    /**
     * 獲取子模塊個數(shù)
     * @return
     */
    public abstract int getSubSocietyCount();

    /**
     * 獲取子模塊
     * @param index 子模塊索引
     * @return
     */
    public abstract Society getSubSociety(int index);

    public abstract void doSomething();
}

創(chuàng)建群眾

/**
 * Created by Afra55 on 2016.07.12 .
 * 社會由群體組成,群體是社會的具體實現(xiàn).
 * 群體又由各個團隊組成.
 */
public class Mass extends Society {

    /**
     * 存儲各個團隊的容器
     */
    private List<Society> societyList = new ArrayList<>();

    public Mass(String name) {
        super(name);
    }

    @Override
    public void addSubSociety(Society society) {
        societyList.add(society);
    }

    @Override
    public void removeSubSociety(Society society) {
        if (societyList.contains(society)) {
            societyList.remove(society);
        }
    }

    @Override
    public int getSubSocietyCount() {
        return societyList.size();
    }

    @Override
    public Society getSubSociety(int index) {
        if (index < getSubSocietyCount()) {
            return societyList.get(index);
        } else {
            throw new IndexOutOfBoundsException("這個團隊不存在");
        }
    }


    @Override
    public void doSomething() {
        System.out.println(name + "群眾是偉大的");
        for (int i = 0 ; i< getSubSocietyCount(); i++) {
            getSubSociety(i).doSomething();
        }
    }
}

創(chuàng)建團隊

/**
 * Created by Afra55 on 2016.07.12 .
 * 個人組成了群眾,個人又有個人組成
 */
public class Team extends Society {

    /**
     * 存儲個人的容器
     */
    private List<Society> societyList = new ArrayList<>();
    
    public Team(String name) {
        super(name);
    }

    @Override
    public void addSubSociety(Society society) {
        societyList.add(society);
    }

    @Override
    public void removeSubSociety(Society society) {
        if (societyList.contains(society)) {
            societyList.remove(society);
        }
    }

    @Override
    public int getSubSocietyCount() {
        return societyList.size();
    }

    @Override
    public Society getSubSociety(int index) {
        if (index < getSubSocietyCount()) {
            return societyList.get(index);
        } else {
            throw new IndexOutOfBoundsException("這個人不存在");
        }
    }

    @Override
    public void doSomething() {
        System.out.println(name + "團隊是偉大的");
        for (int i = 0 ; i< getSubSocietyCount(); i++) {
            getSubSociety(i).doSomething();
        }
    }
}

創(chuàng)建個人

/**
 * Created by Afra55 on 2016.07.12 .
 * 個人組成了團隊,是整個社會的記事
 */
public class People extends Society {

    public People(String name) {
        super(name);
    }

    @Override
    public void addSubSociety(Society society) {
        throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
    }

    @Override
    public void removeSubSociety(Society society) {
        throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
    }

    @Override
    public int getSubSocietyCount() {
        throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
    }

    @Override
    public Society getSubSociety(int index) {
        throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
    }

    @Override
    public void doSomething() {
        System.out.println(name + "是偉大的");
    }
}

使用

public class Main {
    public static void main(String []args) {

        // 創(chuàng)建個人
        People afra55 = new People("Afra55");
        People victor = new People("Victor");
        People aaa = new People("AAA啊哈");

        // 創(chuàng)建 java tema
        Team javaTeam = new Team("Java");
        javaTeam.addSubSociety(afra55);

        // 創(chuàng)建 android team
        Team androidTeam = new Team("Andrid");
        androidTeam.addSubSociety(victor);
        androidTeam.addSubSociety(aaa);

        // 創(chuàng)建群眾
        Mass mass = new Mass("西安");
        mass.addSubSociety(javaTeam);
        mass.addSubSociety(androidTeam);

        mass.doSomething();
    }
}

輸出:

西安群眾是偉大的
Java團隊是偉大的
Afra55是偉大的
Andrid團隊是偉大的
Victor是偉大的
AAA啊哈是偉大的

優(yōu)點

不必關(guān)心對象是個集合還是個體,新增各種成員都很方便,只要繼承基類實現(xiàn)抽象方法即可,不用修改現(xiàn)有的類。
組合模式可以生成復(fù)雜的樹形結(jié)構(gòu),對各個節(jié)點的操作統(tǒng)一而且簡單。

缺點

新增的成員局限于基類,想要統(tǒng)一新功能就要修改基類,所有的繼承基類的類都會進行修改。如果不修改基類,依賴類型,則會對類型進行判斷,增加了代碼復(fù)雜度。


17.適配器模式

當接口不兼容而去兼容接口,或者建立一個可以重復(fù)被不同對象使用的類,或者統(tǒng)一輸出接口,設(shè)配器模式很合適。

下面以藍牙耳機舉例,假設(shè)某款藍牙耳機支持藍牙4.1的設(shè)備不支持4.0的藍牙設(shè)備,現(xiàn)在有個藍牙4.0的手機連接藍牙耳機,需要把藍牙耳機的藍牙設(shè)備版本4.1兼容4.0。

創(chuàng)建接口

 /**
 * Created by Afra55 on 2016.07.13 .
 * 藍牙版本接口
 */
public interface IVersion {

    double getVersion();
}

需要適配的類

/**
 * Created by Afra55 on 2016.07.13 .
 * 藍牙耳機支持的藍牙版本是4.1,不支持4.0
 */
public class BluetoothHeadset implements IVersion {
    @Override
    public double getVersion() {
        return 4.1;
    }
}

類適配器模式

創(chuàng)建適配器

/**
 * Created by Afra55 on 2016.07.13 .
 * 藍牙適配器吧藍牙耳機的藍牙版本轉(zhuǎn)換為4.0,以便連接手機。
 */
public class BluetoothAdapter extends BluetoothHeadset {

    @Override
    public double getVersion() {
        return 4.0;
    }
}

使用

public class Main {
    public static void main(String []args) {
        BluetoothAdapter bluetoothAdapter = new BluetoothAdapter();
        System.out.println(bluetoothAdapter.getVersion());
    }
}

對象適配器模式

創(chuàng)建適配器

/**
 * Created by Afra55 on 2016.07.13 .
 * 藍牙適配器吧藍牙耳機的藍牙版本轉(zhuǎn)換為4.0,以便連接手機。
 */
public class BluetoothAdapter implements IVersion {

    private final BluetoothHeadset bluetoothHeadset;

    public BluetoothAdapter(BluetoothHeadset bluetoothHeadset) {
       this.bluetoothHeadset = bluetoothHeadset;
    }

    public double getOriginVersion() {
        return bluetoothHeadset.getVersion();
    }

    @Override
    public double getVersion() {
        // 在這里進行藍牙版本轉(zhuǎn)換
        return 4.0;
    }
}

使用

public class Main {
    public static void main(String []args) {
        BluetoothHeadset bluetoothHeadset = new BluetoothHeadset();
        BluetoothAdapter bluetoothAdapter = new BluetoothAdapter(bluetoothHeadset);

        System.out.println("藍牙耳機支持的版本: " + bluetoothAdapter.getOriginVersion());
        System.out.println("藍牙耳機適配后的版本: " + bluetoothAdapter.getVersion());
    }
}

優(yōu)點

良好的復(fù)用性和擴展性。

缺點

過多的使用適配器,會造成代碼的復(fù)雜度提升。


18.裝飾模式

要透明且動態(tài)的擴展類的功能時,裝飾模式是個好的選擇。

比如,給人穿不同的衣服,人的 dress 方法是 準備穿衣,現(xiàn)在要擴展功能,穿各種各樣的衣服:

創(chuàng)建人的抽象基類,也可以是接口

/**
 * Created by Afra55 on 2016.07.14 .
 * 人的抽象基類,有個穿衣服的抽象方法
 */
public abstract class People {

    /**
     * 穿衣服
     */
    public abstract void dressed();
}

人的實現(xiàn)類

/**
 * Created by Afra55 on 2016.07.14 .
 * 人的實現(xiàn)類
 */
public class Man extends People {

    private String name;

    public Man(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    /**
     * 只有準備衣服的功能
     */
    @Override
    public void dressed() {
        System.out.println(getName() +" 準備衣服");
    }
}

創(chuàng)建衣服的抽象基類,這里偷懶了

/**
 * Created by Afra55 on 2016.07.14 .
 * 衣服基類,保持了一個 people 的引用
 */
public class Cloth extends People {

    protected People people;

    public Cloth(People people) {
        this.people = people;
    }

    @Override
    public void dressed() {
        people.dressed();
    }
}

創(chuàng)建裙子

/**
 * Created by Afra55 on 2016.07.14 .
 * 裙子
 */
public class Skirt extends Cloth {

    public Skirt(People people) {
        super(people);
    }

    @Override
    public void dressed() {
        super.dressed();
        dressSkirt();
    }

    private void dressSkirt() {
        System.out.println("穿連衣裙");
    }
}

創(chuàng)建西服

/**
 * Created by Afra55 on 2016.07.14 .
 * 西服
 */
public class Suit extends Cloth {

    public Suit(People people) {
        super(people);
    }

    @Override
    public void dressed() {
        super.dressed();
        dressSuit();
    }

    private void dressSuit() {
        System.out.println("穿上西服");
    }
}

使用

public class Main {
    public static void main(String []args) {

        // 創(chuàng)建了一個人
        People you = new Man("Victoor");

        // 創(chuàng)建西服,持有 you 對象
        Cloth suit = new Suit(you);
        suit.dressed();

        // 創(chuàng)建連衣裙,持有 you 對象
        Cloth skirt = new Skirt(you);
        skirt.dressed();

    }
}

優(yōu)點

動態(tài)擴展對象的功能。

缺點


19.享元模式

當有大量的重復(fù)對象出現(xiàn),每次調(diào)用都會去new 一個新的對象,這個對象并沒有什么改變,這個時候使用享元模式較好,可以避免創(chuàng)建多個對象。也可以充當緩沖池使用。

以下以天氣查詢舉例,每天都會有人通過日期查詢天氣,日期相同返回的結(jié)果就相同,當有數(shù)以百萬計的人查詢一個相同的日期時,每次創(chuàng)建新的信息對象會對系統(tǒng)造成很大的負擔(dān),像這類重復(fù)的對象,可以使用緩沖池來讀取緩存里的對象:

創(chuàng)建接口

/**
 * Created by Afra55 on 2016.07.15 .
 * 天氣接口,只獲取天氣情況
 */
public interface IWeather {

    String getWeatherItem();
}

創(chuàng)建實現(xiàn)類

/**
 * Created by Afra55 on 2016.07.15 .
 * 天氣的實現(xiàn)類
 */
public class WeatherItem implements IWeather {

    private String date;

    public WeatherItem(String date) {
        this.date = date;
    }

    @Override
    public String getWeatherItem() {

        String result = "未查到信息";
        // 請忽略偷懶的代碼
        int random = new Random().nextInt(100);
        switch (date) {
            case "今天":
                result = "晴天 "  + random + "攝氏度";
                break;
            case "明天":
                result = "小雨 " + random + "攝氏度";
                break;
            case "后天":
                result = "陰天 " + random + "攝氏度";
                break;
        }

        return result;
    }
}

創(chuàng)建享元工廠

/**
 * Created by Afra55 on 2016.07.15 .
 * 享元模式的體現(xiàn),減少重復(fù)對象的存在,讓同類對象多次復(fù)用
 */
public class WeatherFactory {
    // 使用 map 容器來存儲 天氣 對象,以便在下一次查詢時只拿緩存中的
    private static Map<String, IWeather> weatherMap = new ConcurrentHashMap<>();

    public static IWeather getWeatherInfo(String date) {

        if (weatherMap.containsKey(date)) { // 使用緩存的
            return weatherMap.get(date);
        } else {
            IWeather weather = new WeatherItem(date);  // 創(chuàng)建新對象
            weatherMap.put(date, weather);
            return weather;
        }
    }
}

使用舉例

public class Main {
    public static void main(String []args) {

        for (int i = 0 ;i < 100; i++) {
            System.out.println(WeatherFactory.getWeatherInfo("今天").getWeatherItem());
            System.out.println(WeatherFactory.getWeatherInfo("明天").getWeatherItem());
            System.out.println(WeatherFactory.getWeatherInfo("后天").getWeatherItem());
        }
    }
}

優(yōu)點

減少重復(fù)類的創(chuàng)建,降低內(nèi)存使用。

缺點

邏輯復(fù)雜,代碼復(fù)雜,從緩沖區(qū)中讀取從而增加了讀取時間。


20.外觀模式

當對一個功能模塊進行封裝后,這個功能模塊的調(diào)用變成了一個簡單接口,使用這個功能時不必關(guān)心他的內(nèi)部操作,不去管功能模塊內(nèi)部的修改升級維護等,這種封裝的行為就是外觀模式。

比如 人能 聽說讀寫, 吃喝拉撒,把功能的調(diào)用 都 放在了 人這個類中通過八個簡單的接口實現(xiàn),每次調(diào)用,不會去管他的內(nèi)部實現(xiàn),只要實現(xiàn)功能即可。就跟 Android 去調(diào)用第三方 SDK 一樣,看不到內(nèi)部實現(xiàn),只能調(diào)用封裝好的簡單接口。

優(yōu)點

隱藏了功能細節(jié),能夠靈活的去改變功能模塊,并且讓功能易于使用。

缺點

當業(yè)務(wù)變更,可能要直接去修改功能模塊的細節(jié)。更能的增多,接口也會增多,造成了用戶學(xué)習(xí)成本的提升。


21.橋接模式

當類存在兩個獨立的功能,而且都要進行擴展時,使用橋接模式。

下面以奶茶為例,奶茶有 大杯加糖,大杯加鹽,小杯加糖,小杯加鹽。大杯和小杯屬于杯子大小功能的擴展,加鹽和加糖屬于添加劑功能的擴展,不管誰變化,都沒有交集。

創(chuàng)建實現(xiàn)部分的抽象基類

/**
 * Created by Afra55 on 2016.07.15 .
 * 添加劑
 */
public abstract class Additive {
    public abstract String getAdditive();
}

創(chuàng)建實現(xiàn)部分具體的實現(xiàn)

public class Salt extends Additive {

    @Override
    public String getAdditive() {
        // 具體的實現(xiàn)
        return "加鹽";
    }
}

public class Sugar extends Additive {

    @Override
    public String getAdditive() {
        // 具體的實現(xiàn)
        return "加糖";
    }
}

創(chuàng)建抽象部分的抽象基類

/**
 * Created by Afra55 on 2016.07.15 .
 * 奶茶抽象基類
 */
public abstract class MilkyTea {

    protected Additive additive;

    public MilkyTea(Additive additive) {
        this.additive = additive;
    }

    // 由子類決定奶茶的創(chuàng)建
    public abstract void make();

}

創(chuàng)建抽象部分的子類

/**
 * Created by Afra55 on 2016.07.15 .
 * 大杯奶茶
 */
public class BigMildyTea extends MilkyTea{

    public BigMildyTea(Additive additive) {
        super(additive);
    }

    @Override
    public void make() {
        // 通過調(diào)用實現(xiàn)部分的方法來實現(xiàn)功能
        System.out.println("大杯的" + additive.getAdditive() + "奶茶");
    }
}




/**
 * Created by Afra55 on 2016.07.15 .
 * 小杯奶茶
 */
public class SmallMildyTea extends MilkyTea{

    public SmallMildyTea(Additive additive) {
        super(additive);
    }

    @Override
    public void make() {
        // 通過調(diào)用實現(xiàn)部分的方法來實現(xiàn)功能
        System.out.println("小杯的" + additive.getAdditive() + "奶茶");
    }
}

使用

public class Main {
    public static void main(String []args) {
        BigMildyTea bigMildyTea = new BigMildyTea(new Sugar());
        bigMildyTea.make();

        BigMildyTea bigMildyTea1 = new BigMildyTea(new Salt());
        bigMildyTea1.make();

        SmallMildyTea smallMildyTea = new SmallMildyTea(new Sugar());
        smallMildyTea.make();

        SmallMildyTea smallMildyTea1 = new SmallMildyTea(new Salt());
        smallMildyTea1.make();
    }
}

輸出:

大杯的加糖奶茶
大杯的加鹽奶茶
小杯的加糖奶茶
小杯的加鹽奶茶

優(yōu)點

分離抽象與實現(xiàn),靈活的擴展,對使用的透明。

缺點

不容易設(shè)計,經(jīng)驗尚淺,就是想不到怎么做(笑臉)。


22.抽象工廠模式

先復(fù)習(xí)工廠模式先。
一個對象族有相同的約束時,可以使用工廠模式。
看下面的例子, 鞋子 A3 和 B3 就是個對象族,他們的相同約束是材質(zhì)制作和浸染顏色:

抽象工廠類

/**
 * Created by Afra55 on 2016.07.19 .
 * 鞋子抽象工廠類,用于制造鞋子,這里只定義了兩種,用于浸染顏色和制造材質(zhì)。
 */
public abstract class ShoeFactory {

    /**
     * 制作材質(zhì)
     * @return 材質(zhì)
     */
    public abstract ITexture createTexture();

    /**
     * 浸染顏色
     * @return 顏色
     */
    public abstract IColor changeColor();
}

材質(zhì)相關(guān)

/**
 * Created by Afra55 on 2016.07.19 .
 * 材質(zhì)接口
 */
public interface ITexture {

    void texture();

}

public class CowhideTexture implements ITexture {
    @Override
    public void texture() {
        System.out.println("制作牛皮材質(zhì)");
    }
}

public class DecorativeRndTexture implements ITexture {
    @Override
    public void texture() {
        System.out.println("制作花皮材質(zhì)");
    }
}

顏色相關(guān)

/**
 * Created by Afra55 on 2016.07.19 .
 * 顏色接口
 */
public interface IColor {

    void color();
}

public class GreenColor implements IColor {
    @Override
    public void color() {
        System.out.println("浸染綠色");
    }
}

public class RedColor implements IColor {
    @Override
    public void color() {
        System.out.println("浸染紅色");
    }
}

具體工廠類

/**
 * Created by Afra55 on 2016.07.19 .
 * 綠鞋,牛皮材質(zhì)
 */
public class A2Factory extends ShoeFactory {

    @Override
    public ITexture createTexture() {
        return new CowhideTexture();
    }

    @Override
    public IColor changeColor() {
        return new GreenColor();
    }

    public A2Factory create() {
        System.out.println("開始制作 A2 鞋子:");
        createTexture().texture();
        changeColor().color();
        System.out.println("A2 鞋子制作完成。。。");
        return this;
    }
}


/**
 * Created by Afra55 on 2016.07.19 .
 * 紅鞋,花皮材質(zhì)
 */
public class B3Factory extends ShoeFactory {

    @Override
    public ITexture createTexture() {
        return new DecorativeRndTexture();
    }

    @Override
    public IColor changeColor() {
        return new RedColor();
    }

    public B3Factory create() {
        System.out.println("開始制作 B3 鞋子:");
        createTexture().texture();
        changeColor().color();
        System.out.println("B3 鞋子制作完成。。。");
        return this;
    }
}

使用

public class Main {
    public static void main(String []args) {
        A2Factory a2Factory = new A2Factory();
        a2Factory.create();

        B3Factory b3Factory = new B3Factory();
        b3Factory.create();
    }
}

輸出:

開始制作 A2 鞋子:
制作牛皮材質(zhì)
浸染綠色
A2 鞋子制作完成。。。
開始制作 B3 鞋子:
制作花皮材質(zhì)
浸染紅色
B3 鞋子制作完成。。。

優(yōu)點

分離接口與實現(xiàn)。

缺點

類文件的增加。
每次修改功能,修改抽象工廠,具體工廠都會被修改。


23.解釋器模式

解釋器模式使用較少,主要功能就是解釋,例如 1 # 3 其中把特殊字符 # 解釋成 加號,即 1 # 3 就是 1 + 3,這種行為就是解釋器。

接口

/**
 * Created by Afra55 on 2016.07.19 .
 * 抽象表達式,定義抽象的解釋方法
 */
public abstract class AbstractExpression {

    public abstract void explain();
    
}

具體實現(xiàn)

/**
 * Created by Afra55 on 2016.07.19 .
 * 符號解釋器,例如 解釋 # 為 +
 */
public class CharExpression extends AbstractExpression {
    @Override
    public void explain() {

    }
}

/**
 * Created by Afra55 on 2016.07.19 .
 * 數(shù)字解釋器,例如 1 3,非符號類
 */
public class NumExpression extends AbstractExpression {
    @Override
    public void explain() {

    }
}

優(yōu)點

擴展方便靈活。只需要增加相應(yīng)解釋器即可。

缺點

對于過于繁瑣的內(nèi)容進行解釋,會造成解釋器混亂繁瑣。解釋器要酌情使用。


面向?qū)ο蟮牧蠡驹瓌t回顧

單一職責(zé)原則 S

如題。

開閉原則 O

當功能需求變化時,盡量通過擴展來實現(xiàn)功能,從而避免修改原有代碼。

里氏替換原則 L

依賴繼承和多態(tài)。可以用父類替換子類,而不出錯,不必知道是父類還是子類。關(guān)鍵詞 抽象。

接口隔離原則 I

盡量少的暴露接口,只提供對應(yīng)功能的接口。

依賴倒置原則 D

實現(xiàn)類之間通過抽象進行依賴。即由父類抽象替換子類實現(xiàn),不必關(guān)心實現(xiàn)細節(jié)。

以上通常稱為 SOLID 原則。

迪米特原則 LOD

一個對象對其他對象應(yīng)該有最少的了解,只知道相應(yīng)依賴的方法即可,不關(guān)心具體實現(xiàn)和其他方法。

總結(jié)

面向接口的編程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容