安卓開發你需要知道的設計模式+總結(精簡)+代碼

認真看書,多動手寫demo,就能理解的啦~~加油.

java的設計模式大體上分爲三大類:

  • 創建型模式(5種):工廠方法模式,抽象工廠模式,單例模式,建造者模式,原型模式。
  • 結構型模式(7種):適配器模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。
  • 行爲型模式(11種):策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

設計模式遵循的原則有6個:
1、開閉原則(Open Close Principle)
  對擴展開放,對修改關閉。
2、里氏代換原則(Liskov Substitution Principle)
  只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被複用,而衍生類也能夠在基類的基礎上增加新的行爲。
3、依賴倒轉原則(Dependence Inversion Principle)
  這個是開閉原則的基礎,對接口編程,依賴於抽象而不依賴於具體。
4、接口隔離原則(Interface Segregation Principle)
  使用多個隔離的藉口來降低耦合度。
5、迪米特法則(最少知道原則)(Demeter Principle)
  一個實體應當儘量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
6、合成複用原則(Composite Reuse Principle)
  原則是儘量使用合成/聚合的方式,而不是使用繼承。繼承實際上破壞了類的封裝性,超類的方法可能會被子類修改。

一: 創建型模式
1/單例模式
定義: 確保某一個類只有一個實例,並且提供一個全局訪問點。
對於安卓,基本低併發,所以它的各種寫法都可以用.
用這個穩的:

/**
*第一加載Singleton類時,並沒有實例化,需要調用getInstance()後纔會導致Singleton實例化.
*/
public class Singleton{
	private Singleton(); // 私有
	public static Singleton getInstance(){
		return SingletonHolder.sInstance; //用SingletonHolder來持有Singleton的實例.
	}
	/**
	* Singleton的持有類
	* 內部靜態類
	*/
	private  static  class Singleton{
		private static  final Singleton sInstance = new Singleton() ;
	}
}

2/建造者Builder模式
定義:將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。適用: 那些產品對象的內部結構比較複雜。
舉個例子:

	public class Person {
	    private String name;
	    private int height;

	    public Person(Builder builder) {
	        this.name = builder.name;
	        this.height = builder.height;
	    }
	    
    static class Builder{
	      private String name;
	      private int height; 
	      
		public Builder name(String name) {
	            this.name = name;
	            return this;   //關鍵之處, 返回Builder 自身
	    }
	    
        public Builder height(int height) {
            this.height = height;
            return this;   
        }
        
        public Person build(){
            return new Person(this);    //返回 Person 實例
        }
    }
 }
//-------------測試----------------
public class T1 {
    public static void main(String[] args) {
        Person.Builder builder = new Person.Builder();
        Person person = builder.height(12)
                .name("大王")
                .phone("10086")
                .sex("雄性")
                .weight(120)
                .build();
    }
}

3/原型模式 (克隆)
定義:用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。
一句話概括: 當 new 新建對象費資源( 耗時/創建成本高 ) 時,或者需要保護 源對象 , 可以考慮使用 clone。
場景:
在我們應用程序可能有某些對象的結構比較複雜,但是我們又需要頻繁的使用它們,如果這個時候我們來不斷的新建這個對象勢必會大大損耗系統內存的,這個時候我們需要使用原型模式來對這個結構複雜又要頻繁使用的對象進行克隆。
舉個例子:

public class Document implements Cloneable {    //需要實現 Cloneable 接口  (PS:這裏是淺拷貝)

    private String mText; //文本
    private ArrayList<String> mImages = new ArrayList<>();//圖片
    public String getText() { return mText; }
    public void setText(String text) { mText = text; }
    public ArrayList<String> getImages() { return mImages; }
    public void setImages(ArrayList<String> images) { mImages = images; }

    @Override
    protected Document clone() {
        try {
            Document doc = (Document)super.clone();
            doc.mText = this.mText;
            doc.mImages = this.mImages;
            return doc;
        }catch (CloneNotSupportedException e){
            //dosomething
        }
        return null;
    }
}
//---------------測試------------------
public class Test {
    public static void main(String[] args) {
        Document doc = new Document();
        ArrayList<String> images = new ArrayList<String>();images.add("卡哇伊.jpg");images.add("滑稽.jpg");
        doc.setText("123");
        doc.setImages(images);
        System.out.println("原始文檔的文本:"+doc.getText());
        Document doc2 = doc.clone();
        System.out.println("拷貝原始文檔後,  文檔2修改前的文本:"+doc2.getText());
        doc2.setText("abc"); //修改doc2
        System.out.println("文檔2修改後的文本:"+doc2.getText()); 
        System.out.println("文檔2修改後,原始文檔的文本:"+doc.getText()); 

ps: "這裏改變 ArrayList 內容的話,  源對象 會 受到影響 ,  解決方法是  使用  深拷貝 "
    }
}
//---------------輸出------------------
原始文檔的文本:123
拷貝原始文檔後,  文檔2修改前的文本:123
文檔2修改後的文本:abc
文檔2修改後,原始文檔的文本:123

//深拷貝  看這裏
@Override
    protected Document clone() {
            Document doc = (Document)super.clone();
            doc.mText = this.mText;
            //對mImages進行深度拷貝, 這樣修改mImages內容後,源對象不受影響
            doc.mImages = (ArrayList<String>)this.mImages.clone();  
            return doc;
    }

4/工廠方法 (常用)
作爲抽象工廠模式的孿生兄弟,工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,也就是說工廠方法模式讓實例化推遲到子類
工廠方法模式非常符合“開閉原則”,當需要增加一個新的產品時,我們只需要增加一個具體的產品類和與之對應的具體工廠即可,無須修改原有系統。同時在工廠方法模式中用戶只需要知道生產產品的具體工廠即可,無須關係產品的創建過程,甚至連具體的產品類名稱都不需要知道。雖然他很好的符合了“開閉原則”,但是由於每新增一個新產品時就需要增加兩個類,這樣勢必會導致系統的複雜度增加。
工廠方法模式UML類圖:
工廠方法模式UML類圖
圖解: 具體工廠A(實現了抽象工廠)引用具體產品A(實現了抽象產品)

我的理解: "讓 具體的工廠來決定製造具體的產品"
舉個例子:

"抽象工廠"
public abstract class Factory {
    public abstract Product createProduct();
}
"具體工廠A"   讓工廠子類決定 實例化 某個產品類
public  class FactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ProductA();   ////具體工廠A 製作  具體產品A
    }
}
"具體工廠B"   這裏是FactoryB 製造 產品B
public  class FactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ProductB();   ////具體工廠A 製作  具體產品A
    }
}

"抽象產品"
public abstract class Product {
    public abstract void make();
}
public class ProductA extends Product {
    @Override
    public void make() {
        System.out.println("make ProductA");
    }
}
public class FTest1 {
    public static void main(String[] args) {
        Factory factoryA = new FactoryA();
        Product productA = factoryA.createProduct();
        productA.make();   //工廠A 製作 產品A
        //....其他工廠的製造,比如工廠B 製作 產品B
        Factory factoryB = new FactoryB();
        Product productB = factoryB.createProduct();
        productB.make();   //工廠B 製作 產品B
    }
}

5/抽象工廠模式
所謂抽象工廠模式就是提供一個接口,用於創建相關或者依賴對象的家族,而不需要明確指定具體類。
他允許客戶端使用抽象的接口來創建一組相關的產品,而不需要關係實際產出的具體產品是什麼。這樣一來,客戶就可以從具體的產品中被解耦。它的優點是隔離了具體類的生成,使得客戶端不需要知道什麼被創建了,而缺點就在於新增新的行爲會比較麻煩,因爲當添加一個新的產品對象時,需要更加需要更改接口及其下所有子類。
工廠方法 和 抽象工廠模式 的UML類圖 比較
工廠方法:
工廠方法模式UML類圖
抽象工廠模式
抽象工廠模式UML類圖
我的理解:

將同種類的工廠抽象爲一個抽象工廠, 子類工廠 生產 具體的(多種類的)產品們;
將同種類的產品抽象爲一個抽象產品, 子類 實現 具體的 產品;
舉個例子(附帶代碼):
手機軟件有 安卓系統 或者 ios系統 的軟件, 它們都有製作 短信/撥號軟件的功能, 所以我們可以將抽象出一個 軟件工廠, 抽象製作 短信軟件 和 撥號軟件的方法, 由具體的工廠去實現;
抽象的軟件工廠:
======>安卓軟件工廠: 生產安卓端的短信軟件 和 撥號軟件;
======>IOS軟件工廠: 生產IOS端的短信軟件 和 撥號軟件;
安卓、IOS兩端的xx短信軟件 , 它們屬於同種功能的軟件,只是實現方式不一樣,所以 可以抽象爲 短信軟件 類; 由子類自己去具體實現;撥號軟件同理;
抽象的短信軟件 的產品:
======>安卓短信軟件 和 IOS短信軟件;
抽象的撥號軟件 的產品:
======>安卓短信軟件 和 IOS短信軟件;

"抽象的軟件工廠"
public abstract class SoftFactory {
    public abstract  SMS createSMS();
    public abstract Dialer createDialer();
}
"子類:安卓軟件工廠"
public class AndroidFactory extends SoftFactory {
	@Override
    public SMS createSMS() {
        return new AndroidSMS();  //具體實現  
    }
    @Override
    public Dialer createDialer() {
        return new AndroidDialer();
    }
 "子類:IOS軟件工廠"
 public class IOSFactory extends SoftFactory {
    @Override
    public SMS createSMS() {
        return new IOSSMS();
    }
    @Override
    public Dialer createDialer() {
        return new IOSDialer();
    }
}
 "抽象的短信軟件"
public abstract class SMS {
    public abstract void makeSms();
}
 "子類:安卓短信軟件"
public class AndroidSMS extends SMS {
    @Override
    public void makeSms() {
        System.out.println("製作安卓的短信軟件");
    }
}
.....同理
}
------------測試------------------
public class T1 {

    public static void main(String[] args) {
        //安卓軟件
        AndroidFactory android = new AndroidFactory();
        android.createSMS().makeSms();
        android.createDialer().makeDialer();
        //IOS軟件
        IOSFactory ios = new IOSFactory();
        ios.createSMS().makeSms();
        ios.createDialer().makeDialer();
    }
}
------------輸出------------------
------安卓軟件工廠------
製作安卓的短信軟件
製作安卓的撥號軟件
------IOS軟件工廠------
製作IOS的短信軟件
製作IOS的撥號軟件
----------------------------------

二: 行爲型模式
1/策略模式 (擁有多個方案進行選擇時,避開if-else)
我們知道一件事可能會有很多種方式來實現它,但是其中總有一種最高效的方式,在軟件開發的世界裏面同樣如此,我們也有很多中方法來實現一個功能,但是我們需要一種簡單、高效的方式來實現它,使得系統能夠非常靈活,這就是策略模式。
所以策略模式就是定義了算法族,分別封裝起來,讓他們之前可以互相轉換,此模式然該算法的變化獨立於使用算法的客戶。
在策略模式中它將這些解決問題的方法定義成一個算法羣,每一個方法都對應着一個具體的算法,這裏的一個算法我就稱之爲一個策略。雖然策略模式定義了算法,但是它並不提供算法的選擇,即什麼算法對於什麼問題最合適這是策略模式所不關心的,所以對於策略的選擇還是要客戶端來做。客戶必須要清楚的知道每個算法之間的區別和在什麼時候什麼地方使用什麼策略是最合適的,這樣就增加客戶端的負擔。
同時策略模式也非常完美的符合了"開閉原則",用戶可以在不修改原有系統的基礎上選擇算法或行爲,也可以靈活地增加新的算法或行爲。但是一個策略對應一個類將會是系統產生很多的策略類。

"將多種方法歸類, 抽象爲一個接口, 具體方法實現這個接口"
public interface CalculateStrategy {
    int cacultePrice(int km);
}
public class BusStrategy implements CalculateStrategy {
    @Override
    public int cacultePrice(int km) {
        //bus的相關計算
        //.....省略
        return 5;
    }
}
public class SubwayStrategy implements CalculateStrategy {
    @Override
    public int cacultePrice(int km) {
        //Subway的相關計算
        //.....省略
        return 10;
    }
}
public class TaxiStrategy implements CalculateStrategy {
    @Override
    public int cacultePrice(int km) {
        //Taxi的相關計算
        //.....省略
        return 30;
    }
}
"將策略抽象類傳進來"
public class TranficCalculate {

    CalculateStrategy mStrategy;

    public TranficCalculate(CalculateStrategy strategy) {
        mStrategy = strategy;
    }

    public int calculatePrice(int km){
        return mStrategy.cacultePrice(km);
    }
}
public class T2 {
    public static void main(String[] args) {
    	"出行 , 選擇 不用再if-else了, 傳入具體的策略 即可"
        TranficCalculate calculator = new TranficCalculate(new BusStrategy());
        System.out.println(calculator.calculatePrice(20));
    }
}

2/ 狀態模式 (可參考wifi狀態…)
在很多情況下我們對象的行爲依賴於它的一個或者多個變化的屬性,這些可變的屬性我們稱之爲狀態,也就是說行爲依賴狀態,即當該對象因爲在外部的互動而導致他的狀態發生變化,從而它的行爲也會做出相應的變化。對於這種情況,我們是不能用行爲來控制狀態的變化,而應該站在狀態的角度來思考行爲,即是什麼狀態就要做出什麼樣的行爲。這個就是狀態模式。

所以狀態模式就是允許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。

在狀態模式中我們可以減少大塊的if…else語句,它是允許態轉換邏輯與狀態對象合成一體,但是減少if…else語句的代價就是會換來大量的類,所以狀態模式勢必會增加系統中類或者對象的個數。

同時狀態模式是將所有與某個狀態有關的行爲放到一個類中,並且可以方便地增加新的狀態,只需要改變對象狀態即可改變對象的行爲。但是這樣就會導致系統的結構和實現都會比較複雜,如果使用不當就會導致程序的結構和代碼混亂,不利於維護。

一句話總結:狀態發生改變,行爲發生對應的變化。

狀態模式和策略模式對比:
狀態模式的行爲:平行的、不可替換的;
策略模式的行爲:彼此獨立、可互相替換。

狀態模式UML類圖 ↓
狀態模式UML類圖

"--------------------不同狀態對應着不同的行爲------------"
public interface TVState {  //遙控的一些行爲
    void nextChannel();
    void prevChannel();
    void turnup();
    void turnDown();
}
public class PowerOnState implements TVState {
    @Override
    public void nextChannel() {
        System.out.println("下一個頻道");
    }

    @Override
    public void prevChannel() {
        System.out.println("上一個頻道");
    }

    @Override
    public void turnup() {
        System.out.println("增大音量");
    }

    @Override
    public void turnDown() {
        System.out.println("減小音量");
    }
}
public class PowerOffState implements TVState {
    @Override
    public void nextChannel() {
        System.out.println("關機了無操作");
    }

    @Override
    public void prevChannel() {
        System.out.println("關機了無操作");
    }

    @Override
    public void turnup() {
        System.out.println("關機了無操作");
    }

    @Override
    public void turnDown() {
        System.out.println("關機了無操作");
    }
}
public interface PowerController {
    void powerOn();
    void powerOff();
}
public class TvController implements PowerController {
    private TVState mTVState;

    private void setTVState(TVState TVState) {
        mTVState = TVState;
    }

    @Override
    public void powerOn() {
        setTVState(new PowerOnState());
        System.out.println("-----開機了-----");

    }

    @Override
    public void powerOff() {
        setTVState(new PowerOffState());
        System.out.println("-----關機了-----");
    }

    public void nextChannel(){
        mTVState.nextChannel();
    }
    public void prevChannel(){
        mTVState.prevChannel();
    }
    public void turnDown(){
        mTVState.turnup();
    }
    public void turnup(){
        mTVState.turnup();
    }
}
---------------------------------測試-------------------------------------
public class Test11 {
    public static void main(String[] args) {
        TvController controller = new TvController();
        //開機
        controller.powerOn();
        //開機後的遙控操作
        controller.nextChannel();
        controller.prevChannel();
        controller.turnup();
        controller.turnDown();
        //關機
        controller.powerOff();
        //關機後的遙控操作
        controller.nextChannel();
    }
}
---------------------------------日誌輸出---------------------------------
-----開機了-----
下一個頻道
上一個頻道
增大音量
增大音量
-----關機了-----
關機了無操作

3/責任鏈模式
請求沿着對象鏈傳遞。該將對象組成一條鏈,發送者將請求發給鏈的第一個接收者,並且沿着這條鏈傳遞,直到有一個對象來處理它或者直到最後也沒有對象處理而留在鏈末尾端。

避免請求發送者與接收者耦合在一起,讓多個對象都有可能接收請求,將這些對象連接成一條鏈,並且沿着這條鏈傳遞請求,直到有對象處理它爲止,這就是職責鏈模式。在職責鏈模式中,使得每一個對象都有可能來處理請求,從而實現了請求的發送者和接收者之間的解耦。同時職責鏈模式簡化了對象的結構,它使得每個對象都只需要引用它的後繼者即可,而不必瞭解整條鏈,這樣既提高了系統的靈活性也使得增加新的請求處理類也比較方便。但是在職責鏈中我們不能保證所有的請求都能夠被處理,而且不利於觀察運行時特徵。
責任鏈UML:
責任鏈UML

"重點在這個抽象類"
public abstract class AbstractLeader {
    public AbstractLeader nextLeader;
    public abstract int limit();
    public void handlerRequst(int money){   //子類實現後,調用的就是這個handlerRequst, 進行判斷處理.
        if(money<=limit()){
            handler(money);//當前子類處理
        }else {
            nextLeader.handlerRequst(money);//交給nextLeader處理,調用的是下一個子類的handlerRequst
        }
    }
    public abstract void handler(int money);   //子類具體實現該方法
}
public class Boss extends AbstractLeader {
    @Override
    public int limit() {
        return 50000;
    }
    @Override
    public void handler(int money) {
        System.out.println("我是老闆,處理了:"+money+"錢");
    }
}
public class Manager extends AbstractLeader {
    @Override
    public int limit() {
        return 5000;
    }
    @Override
    public void handler(int money) {
        System.out.println("我是經理,處理了:"+money+"錢");
    }
}
public class TeamLeader extends AbstractLeader {
    @Override
    public int limit() {
        return 1000;
    }

    @Override
    public void handler(int money) {
        System.out.println("我是組長,處理了:"+money+"錢");
    }
}
-------------------測試---------------------
public class Test11 {
    public static void main(String[] args) {
        TeamLeader teamLeader = new TeamLeader();
        Manager manager = new Manager();
        Boss boss = new Boss();

        teamLeader.nextLeader=manager;
        manager.nextLeader=boss;

        teamLeader.handlerRequst(4000);
    }
}
-----------日誌輸出------------
//組長處理不了,交給了上級領導---經理
我是經理,處理了:4000

4/命令模式
有些時候我們想某個對象發送一個請求,但是我們並不知道該請求的具體接收者是誰,具體的處理過程是如何的,們只知道在程序運行中指定具體的請求接收者即可,對於這樣將請求封裝成對象的,我們稱之爲命令模式。所以命令模式將請求封裝成對象,以便使用不同的請求、隊列或者日誌來參數化其他對象。同時命令模式支持可撤銷的操作。

命令模式可以將請求的發送者和接收者之間實現完全的解耦,發送者和接收者之間沒有直接的聯繫,發送者只需要知道如何發送請求命令即可,其餘的可以一概不管,甚至命令是否成功都無需關心。同時我們可以非常方便的增加新的命令,但是可能就是因爲方便和對請求的封裝就會導致系統中會存在過多的具體命令類。

命令模式UML:
命令模式UML

"這裏根據UML類圖寫個簡單的例子吧,具體化(賦予實物)應該也是同理的."

"將   請求/命令  封裝成對象"
public abstract class Command {
    public abstract void excute();
}
public class Recevier {
    public void action(String what){
        System.out.println("接收者,得到的參數:"+what);
    }
}
public class ConcrectCommand extends Command {
    Recevier recevier;  // 接收者
    public ConcrectCommand(Recevier recevier) {
        this.recevier = recevier;
    }
    @Override
    public void excute() {
        recevier.action("具體命令參數: 開燈");
    }
}
"調用者"
public class Invoker {
    Command command;
    public Invoker(Command command) {
        this.command=command;
    }
    public void action(){
        command.excute();
    }
}
---------------測試---------------
public class T1 {
    public static void main(String[] args) {
        
        Recevier recevier = new Recevier();
        
        ConcrectCommand command = new  ConcrectCommand(recevier);
        
        Invoker invoker = new Invoker(command);
        invoker.action();   //執行命令
        "命令模式可以將請求的發送者和接收者之間實現完全的解耦,"
        "發送者和接收者之間沒有直接的聯繫,發送者只需要知道如何發送請求命令即可,"
       " 其餘的可以一概不管,甚至命令是否成功都無需關心。"
    }
}

5/觀察者模式
觀察者模式定義了對象之間的一對多依賴關係,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並且自動更新。

在這裏,發生改變的對象稱之爲觀察目標,而被通知的對象稱之爲觀察者。一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯繫,所以麼可以根據需要增加和刪除觀察者,使得系統更易於擴展。所以觀察者提供了一種對象設計,讓主題和觀察者之間以鬆耦合的方式結合。
插入一個Observable的源碼解析:https://blog.csdn.net/u014285517/article/details/54747811
觀察者模式UML類圖:
觀察者模式UML類圖

使用java.util下的觀察者
/**
 * 被觀察者  (它  發送/通知/更新 to 觀察者)
 * */
public class Sender extends Observable {
    public void post(String arg){
        setChanged();
        notifyObservers(arg);
    }
}
/**
 * 接收者
 */
public class Recevicer implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("收到通知:"+arg);
    }
}
public class T22 {

    public static void main(String[] args) {
        Sender sender = new Sender();
        sender.addObserver(new Recevicer());
        sender.post("2018年9月29日,快放國慶啦!!~~~~");
    }
}

6/備忘錄模式
後悔藥人人都想要,但是事實卻是殘酷的,根本就沒有後悔藥可買,但是也不僅如此,在軟件的世界裏就有後悔藥!備忘錄模式就是一種後悔藥,它給我們的軟件提供後悔藥的機制,通過它可以使系統恢復到某一特定的歷史狀態。

所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣可以在以後將對象恢復到原先保存的狀態。它實現了對信息的封裝,使得客戶不需要關心狀態保存的細節。保存就要消耗資源,所以備忘錄模式的缺點就在於消耗資源。如果類的成員變量過多,勢必會佔用比較大的資源,而且每一次保存都會消耗一定的內存。
備忘錄模式UML類圖
備忘錄模式UML類圖

public class Game {
    private int level = 0; // 等級
    private int checkpoint = 1; //關卡
    private String name = "admin"; //角色名

    //玩遊戲
    public void play(){
        this.level=100;
        this.checkpoint=59;
        this.name = "小明";
        System.out.println("玩遊戲:"+toString());
    }

    //退出遊戲
    public void quit(){
        System.out.println("退出遊戲:");
    }

    public Memoto createMemoto(){
        Memoto memoto = new Memoto();
        memoto.checkpoint=this.checkpoint;
        memoto.level=this.level;
        memoto.name=this.name;
        return memoto;
    }

    public void restore(Memoto memoto){
        this.checkpoint = memoto.checkpoint;
        this.level = memoto.level;
        this.name = memoto.name;
        System.out.println("恢復遊戲:"+toString());
    }


    @Override
    public String toString() {
        return "Game{" +
                "level=" + level +
                ", checkpoint=" + checkpoint +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Memoto {
    public int level = 0; // 等級
    public int checkpoint = 1; //關卡
    public String name = "admin"; //角色名
}
/**
 * 管理存檔   這個除了管理單個Memoto ,也可以是一個Memoto 集合
 * */
public class CareTaker {
    Memoto mMemoto;

    //存檔
    public void archive(Memoto memoto) {
        this.mMemoto = memoto;
    }

    public Memoto getMemoto() {
        return mMemoto;
    }
}
public class T111 {
    public static void main(String[] args) {


        Game game = new Game();
        CareTaker careTaker = new CareTaker();
        //玩遊戲
        game.play();
        //存檔
        careTaker.archive(game.createMemoto());  //存檔存到careTaker
        //退出遊戲
        game.quit();

        //重進遊戲,新建了一個遊戲, 假設careTaker沒被幹掉
        Game newGame = new Game();
        //恢復存檔
        newGame.restore(careTaker.getMemoto());
    }
}

7/迭代器模式
對於迭代在編程過程中我們經常用到,能夠遊走於聚合內的每一個元素,同時還可以提供多種不同的遍歷方式,這就是迭代器模式的設計動機。在我們實際的開發過程中,我們可能會需要根據不同的需求以不同的方式來遍歷整個對象,但是我們又不希望在聚合對象的抽象接口中充斥着各種不同的遍歷操作,於是我們就希望有某個東西能夠以多種不同的方式來遍歷一個聚合對象,這時迭代器模式出現了。

何爲迭代器模式?所謂迭代器模式就是提供一種方法順序訪問一個聚合對象中的各個元素,而不是暴露其內部的表示。迭代器模式是將迭代元素的責任交給迭代器,而不是聚合對象,我們甚至在不需要知道該聚合對象的內部結構就可以實現該聚合對象的迭代。

通過迭代器模式,使得聚合對象的結構更加簡單,它不需要關注它元素的遍歷,只需要專注它應該專注的事情,這樣就更加符合單一職責原則了。

迭代器模式UML類圖
在這裏插入圖片描述

迭代器的接口
public interface MyIterator {
    boolean hasNext();
    Object next();
}
具體迭代器,這裏是數組
public class ArrayIterator<T> implements MyIterator {
    private String[] array;
    private int position;
    public ArrayIterator(String[] array) {
        this.array = array;
    }
    @Override
    public boolean hasNext() {
        return !(position>array.length-1 || array[position]==null);
    }
    @Override
    public Object next() {
        return array[position++];
    }
}
具體迭代器,這裏是列表
public class ListIterator<T> implements MyIterator {
    private List<T> array;
    private int position;
    public ListIterator(List<T> args) {
        this.array = args;
    }
    @Override
    public boolean hasNext() {
        return !(position>array.size()-1 || array.get(position)==null);
    }
    @Override
    public Object next() {
        return array.get(position++);
    }
}
獲取迭代器的接口,重點
public interface Company {
    MyIterator iterator();
}
實現接口,獲取具體迭代器
public class ACompany implements Company {
    private List<String> list = new ArrayList<>();
    public ACompany() {
        list.add("大王1");
        list.add("大王2");
    }
    @Override
    public MyIterator iterator() {
        return new ListIterator<>(list);   //重點
    }
}
實現接口,獲取具體迭代器
public class BCompany implements Company {
    private String[] array = new String[4];
    public BCompany() {
        array[0]="呵呵1";
        array[1]="呵呵2";
        array[2]="呵呵3";
    }
    public String[] getData(){
        return array;
    }
    @Override
    public MyIterator iterator() {
        return new ArrayIterator<>(array);
    }
}
測試
public class T {
    public static void main(String[] args) {
        ACompany aCompany = new ACompany();
        BCompany bCompany = new BCompany();
		//aCompany.iterator()  獲取具體迭代器
        check(aCompany.iterator());  //將具體迭代器傳入
        check(bCompany.iterator());
    }
    private static void check(MyIterator iterator){
    	//遍歷
        while (iterator.hasNext()){  
            System.out.println(iterator.next());  
        }
    }
}

8/模板模式
有些時候我們做某幾件事情的步驟都差不多,僅有那麼一小點的不同,在軟件開發的世界裏同樣如此,如果我們都將這些步驟都一一做的話,費時費力不討好。所以我們可以將這些步驟分解、封裝起來,然後利用繼承的方式來繼承即可,當然不同的可以自己重寫實現嘛!這就是模板方法模式提供的解決方案。

所謂模板方法模式就是在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。

模板方法模式就是基於繼承的代碼複用技術的。在模板方法模式中,我們可以將相同部分的代碼放在父類中,而將不同的代碼放入不同的子類中。也就是說我們需要聲明一個抽象的父類,將部分邏輯以具體方法以及具體構造函數的形式實現,然後聲明一些抽象方法讓子類來實現剩餘的邏輯,不同的子類可以以不同的方式來實現這些邏輯。所以模板方法的模板其實就是一個普通的方法,只不過這個方法是將算法實現的步驟封裝起來的。

public abstract class AbComputer {
    public void checkHardware(){
        System.out.println("檢查硬件");
    }
    public void loadOS(){
        System.out.println("進入系統");
    }
    public void login(){
        System.out.println("進入系統");
    }
    public void show(){
        System.out.println("顯示桌面");
    }
    public final void startup(){
        System.out.println("---開機...---");
        checkHardware();
        loadOS();
        login();
        show();
        System.out.println("---開機完成--");
    }
}
public class NormalComputer extends AbComputer {

    public NormalComputer() {
        System.out.println("菜鳥的電腦");
    }

    @Override
    public void login() {
        System.out.println("沒有密碼,直接登錄喔");
    }
}
public class ProComputer extends AbComputer {
    public ProComputer() {
        System.out.println("專業的電腦");
    }

    @Override
    public void login() {
        System.out.println("需要鍵入密碼才能登錄");
    }
}
public class T {
    public static void main(String[] args) {
        AbComputer computer = new ProComputer();
        computer.startup();
    }
}

9/訪問者模式
訪問者模式俗稱23大設計模式中最難的一個。除了結構複雜外,理解也比較難。在我們軟件開發中我們可能會對同一個對象有不同的處理,如果我們都做分別的處理,將會產生災難性的錯誤。對於這種問題,訪問者模式提供了比較好的解決方案。訪問者模式即表示一個作用於某對象結構中的各元素的操作,它使我們可以在不改變各元素的類的前提下定義作用於這些元素的新操作。

訪問者模式的目的是封裝一些施加於某種數據結構元素之上的操作,一旦這些操作需要修改的話,接受這個操作的數據結構可以保持不變。爲不同類型的元素提供多種訪問操作方式,且可以在不修改原有系統的情況下增加新的操作方式。同時我們還需要明確一點那就是訪問者模式是適用於那些數據結構比較穩定的,因爲他是將數據的操作與數據結構進行分離了,如果某個系統的數據結構相對穩定,但是操作算法易於變化的話,就比較適用適用訪問者模式,因爲訪問者模式使得算法操作的增加變得比較簡單了。
在這裏插入圖片描述

"抽象訪問者"
public interface Visitor {

    void visit(Engineer engineer);
    void visit(Manager manager);
}

"具體訪問者"
public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師:"+engineer.name+",代碼行數:"+engineer.getCodeLines());
    }
    @Override
    public void visit(Manager manager) {
        System.out.println("經理:"+manager.name+",新產品量:"+manager.getProducts());
    }
}

"具體訪問者"
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師:"+engineer.name+",KPI:"+engineer.KPI);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理:"+manager.name+",KPI:"+manager.KPI+",新產品量:"+manager.getProducts());
    }
}

"抽象元素"
public abstract class Staff {
    public String name;
    public int KPI;

    public Staff(String name) {
        this.name = name;
        this.KPI = new Random().nextInt(10);
    }

    public abstract void accept(Visitor visitor);
}

"具體元素"
public class Engineer extends Staff {

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

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

    public int getCodeLines(){
        return new Random().nextInt(10*10000);
    }
}

"具體元素"
public class Manager extends Staff {

    private int products;

    public Manager(String name) {
        super(name);
        products = new Random().nextInt(10);
    }

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

    public int getProducts(){
        return products;
    }
}

"對象結構-----元素被使用"
public class BusinessReport {
    private List<Staff> mStaffs = new LinkedList<Staff>();
    public BusinessReport() {
        mStaffs.add(new Manager("王經理"));
        mStaffs.add(new Engineer("工程師-Shanwm"));
        mStaffs.add(new Engineer("工程師-Canwm"));
        mStaffs.add(new Engineer("工程師-Xii"));
        mStaffs.add(new Engineer("工程師-Jiuan"));
    }

    public void showReport(Visitor visitor){
        System.out.println("--------------------------");
        for(Staff staff:mStaffs){
            staff.accept(visitor);
        }
    }
}

"調用  對象結構,"
public class Client {

    public static void main(String[] args) {
        BusinessReport report = new BusinessReport();
        report.showReport(new CEOVisitor());
        report.showReport(new CTOVisitor());

    }
}
---------"輸出"
--------------------------
經理:王經理,KPI:4,新產品量:7
工程師:工程師-Shanwm,KPI:0
工程師:工程師-Canwm,KPI:8
工程師:工程師-Xii,KPI:9
工程師:工程師-Jiuan,KPI:9
--------------------------
經理:王經理,新產品量:7
工程師:工程師-Shanwm,代碼行數:24767
工程師:工程師-Canwm,代碼行數:98568
工程師:工程師-Xii,代碼行數:5828
工程師:工程師-Jiuan,代碼行數:42639

**10/ 中介者模式 **
租房各位都有過的經歷吧!在這個過程中中介結構扮演着很重要的角色,它在這裏起到一箇中間者的作用,給我們和房主互相傳遞信息。在外面軟件的世界裏同樣需要這樣一箇中間者。在我們的系統中有時候會存在着對象與對象之間存在着很強、複雜的關聯關係,如果讓他們之間有直接的聯繫的話,必定會導致整個系統變得非常複雜,而且可擴展性很差!在前面我們就知道如果兩個類之間沒有不必彼此通信,我們就不應該讓他們有直接的關聯關係,如果實在是需要通信的話,我們可以通過第三者來轉發他們的請求。同樣,這裏我們利用中介者來解決這個問題。

所謂中介者模式就是用一箇中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。在中介者模式中,中介對象用來封裝對象之間的關係,各個對象可以不需要知道具體的信息通過中介者對象就可以實現相互通信。它減少了對象之間的互相關係,提供了系統可複用性,簡化了系統的結構。

在中介者模式中,各個對象不需要互相知道了解,他們只需要知道中介者對象即可,但是中介者對象就必須要知道所有的對象和他們之間的關聯關係,正是因爲這樣就導致了中介者對象的結構過於複雜,承擔了過多的職責,同時它也是整個系統的核心所在,它有問題將會導致整個系統的問題。所以如果在系統的設計過程中如果出現“多對多”的複雜關係羣時,千萬別急着使用中介者模式,而是要仔細思考是不是您設計的系統存在問題。
在這裏插入圖片描述


//抽象中介者
public abstract class Mediator {

    public abstract void change(Colleague colleague);


}
//子配件
public abstract class Colleague {
    protected Mediator mMediator;

    public Colleague(Mediator mediator) {
        mMediator = mediator;
    }
}
public class CPU extends Colleague {

    private String dataVideo,dataSound;


    public CPU(Mediator mediator) {
        super(mediator);
    }

    public String getDataSound() {
        return dataSound;
    }

    public String getDataVideo() {
        return dataVideo;
    }

    public void decodeData(String data){
        String[] tmp = data.split(",");
        //
        dataVideo = tmp[0];
        dataSound = tmp[1];

        mMediator.change(this);
    }
}
public class CDDevice extends Colleague {

    private String data;

    public CDDevice(Mediator mediator) {
        super(mediator);
    }

    public String read(){
        return data;
    }

    public void load(){
        data = "視頻數據[馬克思主義基本原理.mp4],音頻數據[張召忠說.mp3]";

        mMediator.change(this);
    }
}
public class GraphicsCard extends Colleague {
    public GraphicsCard(Mediator mediator) {
        super(mediator);
    }

    public void vedioPlay(String data){
        System.out.println("播放視頻:"+data);
    }
}
public class SoundCard extends Colleague {

    public SoundCard(Mediator mediator) {
        super(mediator);
    }

    public void soundPlay(String data){
        System.out.println("播放音頻:"+data);
    }
}
public class MainBoard extends Mediator {

    private CDDevice mCDDevice;
    private CPU mCPU;
    private SoundCard mSoundCard;
    private GraphicsCard mGraphicsCard;


    @Override
    public void change(Colleague colleague) {
        if(colleague==mCDDevice){
            handleCD((CDDevice)colleague);
        }else if(colleague==mCPU){
            handleCD((CPU)colleague);
        }
    }

    private void handleCD(CDDevice cdDevice) {
        mCPU.decodeData(cdDevice.read());
    }

    private void handleCD(CPU cpu) {

        mSoundCard.soundPlay(cpu.getDataSound());
        mGraphicsCard.vedioPlay(cpu.getDataVideo());
    }


    public void setCDDevice(CDDevice CDDevice) {
        mCDDevice = CDDevice;
    }

    public void setCPU(CPU CPU) {
        mCPU = CPU;
    }

    public void setSoundCard(SoundCard soundCard) {
        mSoundCard = soundCard;
    }

    public void setGraphicsCard(GraphicsCard graphicsCard) {
        mGraphicsCard = graphicsCard;
    }
}
public class Client {

    public static void main(String[] args) {

        MainBoard mainBoard = new MainBoard();
        CDDevice cdDevice = new CDDevice(mainBoard);
        GraphicsCard graphicsCard = new GraphicsCard(mainBoard);
        SoundCard soundCard = new SoundCard(mainBoard);
        CPU cpu = new CPU(mainBoard);

        mainBoard.setCDDevice(cdDevice);
        mainBoard.setCPU(cpu);
        mainBoard.setGraphicsCard(graphicsCard);
        mainBoard.setSoundCard(soundCard);

        cdDevice.load();

    }
}
----"輸出"
播放音頻:音頻數據[張召忠說.mp3]
播放視頻:視頻數據[馬克思主義基本原理.mp4]

三: 結構型模式
**1/ 代理模式 **
代理模式就是給一個對象提供一個代理,並由代理對象控制對原對象的引用。它使得客戶不能直接與真正的目標對象通信。代理對象是目標對象的代表,其他需要與這個目標對象打交道的操作都是和這個代理對象在交涉。

代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了的作用和保護了目標對象的,同時也在一定程度上面減少了系統的耦合度。
在這裏插入圖片描述

public class ProxySubject extends Subject {
    private RealSubject realSubject;
    //代理模式/委託模式
    //引用真實的對象
    public void setRealSubject(RealSubject realSubject){
        this.realSubject = realSubject;
    }

    @Override
    public void visit() {
        realSubject.visit();
    }
}
public abstract class Subject {
    public abstract void visit();
}

public class RealSubject extends Subject {
    @Override
    public void visit() {
        System.out.println("Real Subject");
    }
}
public class Client {

    public static void main(String[] args) {

        RealSubject realSubject = new RealSubject();

        ProxySubject proxySubject = new ProxySubject();
        proxySubject.setRealSubject(realSubject);

        proxySubject.visit();

    }
}

動態代理

public class DynamicProxy implements InvocationHandler {

    private Object obj;


    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result = method.invoke(obj,args);


        return result;
    }

    public ILawsuit getRealProxy(ClassLoader loader) {
        return (ILawsuit)Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},this);
    }

}

public interface ILawsuit {

    void sumit();


    void finish();
}

public class XiaoMing implements ILawsuit {
    @Override
    public void sumit() {
        System.out.println("XiaoMing: sumit");
    }



    @Override
    public void finish() {
        System.out.println("XiaoMing: finish");
    }
}

public class Client {

    public static void main(String[] args) {

        XiaoMing xiaoMing = new XiaoMing();


        DynamicProxy proxy = new DynamicProxy(xiaoMing);

        ClassLoader loader = xiaoMing.getClass().getClassLoader();

        ILawsuit lawyer = proxy.getRealProxy(loader);

        lawyer.sumit();

        lawyer.finish();


    }
}

**2/ 組合模式 **
組合模式組合多個對象形成樹形結構以表示“整體-部分”的結構層次。它定義瞭如何將容器對象和葉子對象進行遞歸組合,使得客戶在使用的過程中無須進行區分,可以對他們進行一致的處理。在使用組合模式中需要注意一點也是組合模式最關鍵的地方:葉子對象和組合對象實現相同的接口。這就是組合模式能夠將葉子節點和對象節點進行一致處理的原因。

雖然組合模式能夠清晰地定義分層次的複雜對象,也使得增加新構件也更容易,但是這樣就導致了系統的設計變得更加抽象,如果系統的業務規則比較複雜的話,使用組合模式就有一定的挑戰了。

在這裏插入圖片描述

//抽象根節點
public abstract class Component {
    String name;

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

    public abstract void doSomethings();
}

public class Composite extends Component {

   private List<Component> mList = new ArrayList<>();

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

    @Override
    public void doSomethings() {

        if(null!=mList){
            System.out.println("--------"+name);
            System.out.println("枝幹節點:"+name);
            for (Component c:mList){
                c.doSomethings();
            }
            System.out.println("--------"+name);
        }
    }

    public void add(Component c){
        mList.add(c);
    }

    public void remove(Component c){
        mList.remove(c);
    }

    public void getChild(int index){
        mList.get(index);
    }
}

public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

    @Override
    public void doSomethings() {
        System.out.println("葉子構件:"+name);
    }
}

public class Client {


    public static void main(String[] args) {
        Composite root = new Composite("root");
        Composite child = new Composite("child");


        Composite branch1 = new Composite("branch1");
        Composite branch2 = new Composite("branch2");
        Composite branch3 = new Composite("branch3");

        branch1.add(new Leaf("leaf1"));
        branch2.add(new Leaf("leaf2"));


        child.add(new Leaf("leaf3"));
        child.add(new Leaf("leaf4"));

        branch3.add(child);

        root.add(branch1);
        root.add(branch2);
        root.add(branch3);

        root.doSomethings();
    }
}

**3/ 適配器模式 **
在我們的應用程序中我們可能需要將兩個不同接口的類來進行通信,在不修改這兩個的前提下我們可能會需要某個中間件來完成這個銜接的過程。這個中間件就是適配器。所謂適配器模式就是將一個類的接口,轉換成客戶期望的另一個接口。它可以讓原本兩個不兼容的接口能夠無縫完成對接。

作爲中間件的適配器將目標類和適配者解耦,增加了類的透明性和可複用性。
在這裏插入圖片描述

public interface Volt5 {
    public int getVolt5();
}

public class Volt220 {
    public int getVolt220(){
        return 220;
    }
}
public class Volt5Adapter implements Volt5 {

    Volt220 mVolt220;

    public Volt5Adapter(Volt220 volt220) {
        mVolt220 = volt220;
    }

    public int getVolt220(){
        return mVolt220.getVolt220();
    }

    @Override
    public int getVolt5() {
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        Volt220 volt220 = new Volt220();
        Volt5Adapter adapter = new Volt5Adapter(volt220);
        System.out.println(adapter.getVolt5());   //  "220V的電壓轉5V"
        System.out.println(adapter.getVolt220());
    }
}

**4/ 裝飾模式 **
我們可以通過繼承和組合的方式來給一個對象添加行爲,雖然使用繼承能夠很好擁有父類的行爲,但是它存在幾個缺陷:一、對象之間的關係複雜的話,系統變得複雜不利於維護。二、容易產生“類爆炸”現象。三、是靜態的。在這裏我們可以通過使用裝飾者模式來解決這個問題。

裝飾者模式,動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更加有彈性的替代方案。雖然裝飾者模式能夠動態將責任附加到對象上,但是他會產生許多的細小對象,增加了系統的複雜度。

在這裏插入圖片描述

public abstract class Person {
    public abstract void dress();
}

public class Boy extends Person {
    @Override
    public void dress() {
        System.out.println("穿着內衣內褲");
    }
}

public abstract class PersonCloth extends Person {


    protected Person mPerson;

    public PersonCloth(Person person) {
        mPerson = person;
    }

    @Override
    public void dress() {
        mPerson.dress();
    }
}

public class CheapCloth extends PersonCloth {
    public CheapCloth(Person person) {
        super(person);
    }



    private void dressShorts(){
        System.out.println("便宜的短褲+短袖");
    }

    @Override
    public void dress() {
        //也可以在這裏寫,看需求
        super.dress();
        dressShorts();
    }
}

public class ExpensiveCloth extends PersonCloth {
    public ExpensiveCloth(Person person) {
        super(person);
    }

    @Override
    public void dress() {
        super.dress();
        dressShorts();
        dressJean();
        dressLeather();
    }

    private void dressShorts(){
        System.out.println("貴的短袖");
    }
    private void dressJean(){
        System.out.println("貴的牛仔褲");
    }
    private void dressLeather(){
        System.out.println("貴的皮衣");
    }
}


public class Test {

    public static void main(String[] args) {
        Boy boy = new Boy();
        PersonCloth expensiveCloth = new ExpensiveCloth(boy);
        expensiveCloth.dress();
        System.out.println("-----");
        PersonCloth cheapCloth = new CheapCloth(boy);
        cheapCloth.dress();
    }
}
-------輸出
穿着內衣內褲
貴的短袖
貴的牛仔褲
貴的皮衣
-----
穿着內衣內褲
便宜的短褲+短袖

5/亨元模式
在一個系統中對象會使得內存佔用過多,特別是那些大量重複的對象,這就是對系統資源的極大浪費。享元模式對對象的重用提供了一種解決方案,它使用共享技術對相同或者相似對象實現重用。享元模式就是運行共享技術有效地支持大量細粒度對象的複用。系統使用少量對象,而且這些都比較相似,狀態變化小,可以實現對象的多次複用。這裏有一點要注意:享元模式要求能夠共享的對象必須是細粒度對象。享元模式通過共享技術使得系統中的對象個數大大減少了,同時享元模式使用了內部狀態和外部狀態,同時外部狀態相對獨立,不會影響到內部狀態,所以享元模式能夠使得享元對象在不同的環境下被共享。同時正是分爲了內部狀態和外部狀態,享元模式會使得系統變得更加複雜,同時也會導致讀取外部狀態所消耗的時間過長。
在這裏插入圖片描述

public interface Ticket {
    void showTicketInfo(String bunk);  //bunk 鋪位
}

public class TrainTicket implements Ticket {

    String from;
    String to;
    String bunk;
    int price;

    public TrainTicket(String from, String to) {
        this.from = from;
        this.to = to;
    }

    @Override
    public void showTicketInfo(String bunk) {
        this.bunk = bunk;
        setPrice();
        System.out.println("購票信息:"+toString());
    }


    //票價不固定, 查詢系統可得
    private  void setPrice(){
//        System.out.println("此時的價位 已更新");
        price = new Random().nextInt(300);
    }

    @Override
    public String toString() {
        return "TrainTicket{" +
                "from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", bunk='" + bunk + '\'' +
                ", price=" + price +
                '}';
    }
}
public class TicketFactory {

    static Map<String,Ticket> ticketMap = new ConcurrentHashMap<>();

    public static Ticket getTicket(String from, String to){

        String key = from + "-" +to;

        if(ticketMap.containsKey(key)){
            System.out.println("使用緩存==>"+key);
            return ticketMap.get(key);
        }else {
            System.out.println("創建新對象==>"+key);
            TrainTicket trainTicket = new TrainTicket(from,to);
            ticketMap.put(key,trainTicket);
            return trainTicket;
        }


    }


}

public class Client {

    public static void main(String[] args) {
        Ticket t1 = TicketFactory.getTicket("北京","青島");
        t1.showTicketInfo("上鋪");
        Ticket t2 = TicketFactory.getTicket("北京","青島");
        t2.showTicketInfo("下鋪");
        Ticket t3 = TicketFactory.getTicket("北京","青島");
        t3.showTicketInfo("上鋪");
        Ticket t4 = TicketFactory.getTicket("北京","廣州");
        t4.showTicketInfo("上鋪");
        Ticket t5 = TicketFactory.getTicket("北京","廣州");
        t5.showTicketInfo("下鋪");
    }
}
----------------輸出
創建新對象==>北京-青島
購票信息:TrainTicket{from='北京', to='青島', bunk='上鋪', price=54}
使用緩存==>北京-青島
購票信息:TrainTicket{from='北京', to='青島', bunk='下鋪', price=290}
使用緩存==>北京-青島
購票信息:TrainTicket{from='北京', to='青島', bunk='上鋪', price=200}
創建新對象==>北京-廣州
購票信息:TrainTicket{from='北京', to='廣州', bunk='上鋪', price=276}
使用緩存==>北京-廣州
購票信息:TrainTicket{from='北京', to='廣州', bunk='下鋪', price=144}


6/外觀模式

我們都知道類與類之間的耦合越低,那麼可複用性就越好,如果兩個類不必彼此通信,那麼就不要讓這兩個類發生直接的相互關係,如果需要調用裏面的方法,可以通過第三者來轉發調用。外觀模式非常好的詮釋了這段話。外觀模式提供了一個統一的接口,用來訪問子系統中的一羣接口。它讓一個應用程序中子系統間的相互依賴關係減少到了最少,它給子系統提供了一個簡單、單一的屏障,客戶通過這個屏障來與子系統進行通信。通過使用外觀模式,使得客戶對子系統的引用變得簡單了,實現了客戶與子系統之間的鬆耦合。但是它違背了“開閉原則”,因爲增加新的子系統可能需要修改外觀類或客戶端的源代碼。
在這裏插入圖片描述

public interface Camera {
    void open();
    void takePhoto();
    void close();
}
public class CameraImpl implements Camera {
    @Override
    public void open() {
        System.out.println("打開相機");
    }

    @Override
    public void takePhoto() {
        System.out.println("拍照");
    }

    @Override
    public void close() {
        System.out.println("關閉相機");
    }
}
public interface Phone {
    void dail();
    void hangup();//掛斷
}
public class PhoneImpl implements Phone {
    @Override
    public void dail() {
        System.out.println("打電話");
    }

    @Override
    public void hangup() {
        System.out.println("掛斷電話");
    }
}

public class MobilePhone {
    private Phone mPhone = new PhoneImpl();
    private Camera mCamera = new CameraImpl();


    public void dail(){
        mPhone.dail();
    }

    public void videoChat(){
        System.out.println("-->視頻聊天接通ing");
        mCamera.open();
        mPhone.dail();
    }

    public void hangup(){
        mPhone.hangup();
    }

    public void takePhoto(){
        mCamera.takePhoto();
    }

    public void closeCamera(){
        mCamera.close();
    }

}


public class PhoneTest {


    public static void main(String[] args) {
        MobilePhone mobilePhone = new MobilePhone();
        //mobilePhone.dail();
        mobilePhone.takePhoto();
        mobilePhone.videoChat();
    }
}

**7/橋接模式 **

如果說某個系統能夠從多個角度來進行分類,且每一種分類都可能會變化,那麼我們需要做的就是講這多個角度分離出來,使得他們能獨立變化,減少他們之間的耦合,這個分離過程就使用了橋接模式。所謂橋接模式就是講抽象部分和實現部分隔離開來,使得他們能夠獨立變化。

橋接模式將繼承關係轉化成關聯關係,封裝了變化,完成了解耦,減少了系統中類的數量,也減少了代碼量。

在這裏插入圖片描述

public abstract class CoffeeAdditives {

    //由子類決定加什麼
    public abstract String addSth();
}
public abstract class Coffee {
    protected CoffeeAdditives additives;

    public Coffee(CoffeeAdditives additives) {
        this.additives = additives;
    }

    public abstract void makeCoffee();
}
public class LargeCoffee extends Coffee {

    public LargeCoffee(CoffeeAdditives additives) {
        super(additives);
    }

    @Override
    public void makeCoffee() {
        System.out.println("大杯的+"+additives.addSth()+"+咖啡");
    }
}
public class SmallCoffee extends Coffee {

    public SmallCoffee(CoffeeAdditives additives) {
        super(additives);
    }

    @Override
    public void makeCoffee() {
        System.out.println("小杯的+"+additives.addSth()+"+咖啡");
    }
}
public class Sugar extends CoffeeAdditives {
    @Override
    public String addSth() {
        return "加糖的";
    }
}

public class Ordinary extends CoffeeAdditives {
    @Override
    public String addSth() {
        return "原味的";
    }
}

public class Main {
    public static void main(String[] args) {
//        材料
        Ordinary ordinary = new Ordinary();
        Sugar sugar = new Sugar();

//        各種口味的咖啡
        //大杯
        LargeCoffee largeCoffeeOrdinary = new LargeCoffee(ordinary);
        largeCoffeeOrdinary.makeCoffee();
        LargeCoffee largeCoffeeSugar = new LargeCoffee(sugar);
        largeCoffeeSugar.makeCoffee();
        //小杯
        SmallCoffee smallCoffeeOrdinary = new SmallCoffee(ordinary);
        smallCoffeeOrdinary.makeCoffee();
        SmallCoffee smallCoffeeSugar = new SmallCoffee(sugar);
        smallCoffeeSugar.makeCoffee();
    }
}
//輸出
//大杯的+原味的+咖啡
//大杯的+加糖的+咖啡
//小杯的+原味的+咖啡
//小杯的+加糖的+咖啡

PS:縮減篇幅,後續每個模式改爲鏈接.

學習參考:
·《Head First設計模式》
·《安卓源碼設計模式》
·https://www.cnblogs.com/pony1223/p/7608955.html
·https://www.cnblogs.com/malihe/p/6891920.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章