Android的設(shè)計(jì)模式-備忘錄模式

前言

Android的設(shè)計(jì)模式系列文章介紹,歡迎關(guān)注,持續(xù)更新中:

Android的設(shè)計(jì)模式-設(shè)計(jì)模式的六大原則
一句話總結(jié)23種設(shè)計(jì)模式則
創(chuàng)建型模式:
Android的設(shè)計(jì)模式-單例模式
Android的設(shè)計(jì)模式-建造者模式
Android的設(shè)計(jì)模式-工廠方法模式
Android的設(shè)計(jì)模式-簡(jiǎn)單工廠模式
Android的設(shè)計(jì)模式-抽象工廠模式
Android的設(shè)計(jì)模式-原型模式
行為型模式:
Android的設(shè)計(jì)模式-策略模式
Android的設(shè)計(jì)模式-狀態(tài)模式
Android的設(shè)計(jì)模式-責(zé)任鏈模式
Android的設(shè)計(jì)模式-觀察者模式
Android的設(shè)計(jì)模式-模板方法模式
Android的設(shè)計(jì)模式-迭代器模式
Android的設(shè)計(jì)模式-備忘錄模式
Android的設(shè)計(jì)模式-訪問(wèn)者模式
Android的設(shè)計(jì)模式-中介者模式
Android的設(shè)計(jì)模式-解釋器模式
Android的設(shè)計(jì)模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計(jì)模式-代理模式
Android的設(shè)計(jì)模式-組合模式
Android的設(shè)計(jì)模式-適配器模式
Android的設(shè)計(jì)模式-裝飾者模式
Android的設(shè)計(jì)模式-享元模式
Android的設(shè)計(jì)模式-外觀模式
Android的設(shè)計(jì)模式-橋接模式

1.定義

在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),這樣以后就可以將該對(duì)象恢復(fù)到先前保存的狀態(tài)。

2.介紹

  • 備忘錄模式屬于行為型模式。
  • 備忘錄模式比較適合用于功能復(fù)雜,但是需要維護(hù)和紀(jì)錄歷史的地方,或者是需要保存一個(gè)或者多個(gè)屬性的地方;在未來(lái)某個(gè)時(shí)刻需要時(shí),將其還原到原來(lái)紀(jì)錄的狀態(tài)。

3.UML類圖

備忘錄模式UML類圖.jpg
角色說(shuō)明:
  • Originator(發(fā)起人角色):負(fù)責(zé)創(chuàng)建一個(gè)備忘錄(Memoto),能夠記錄內(nèi)部狀態(tài),以及恢復(fù)原來(lái)記錄的狀態(tài)。并且能夠決定哪些狀態(tài)是需要備忘的。
  • Memoto(備忘錄角色):將發(fā)起人(Originator)對(duì)象的內(nèi)部狀態(tài)存儲(chǔ)起來(lái);并且可以防止發(fā)起人(Originator)之外的對(duì)象訪問(wèn)備忘錄(Memoto)。
  • Caretaker(負(fù)責(zé)人角色):負(fù)責(zé)保存?zhèn)渫洠∕emoto),不能對(duì)備忘錄(Memoto)的內(nèi)容進(jìn)行操作和訪問(wèn),只能將備忘錄傳遞給其他對(duì)象。

4.實(shí)現(xiàn)

以游戲存檔為例子:

4.1 創(chuàng)建發(fā)起人角色

這里則是游戲類,游戲類提供存檔和讀檔的功能:

    public class Game {//游戲類
        private int mLevel = 1;//等級(jí)
        private int mCoin = 0;//金幣數(shù)量

        @Override
        public String toString() {
            return "game{" +
                    "mLevel=" + mLevel +
                    ", mCoin=" + mCoin +
                    '}';
        }

        public void play() {
            System.out.println("升級(jí)了");
            mLevel++;
            System.out.println("當(dāng)前等級(jí)為:" + mLevel);
            System.out.println("獲得金幣:32");
            mCoin += 32;
            System.out.println("當(dāng)前金幣數(shù)量為:" + mCoin);
        }

        public void exit() {
            System.out.println("退出游戲");
            System.out.println("退出游戲時(shí)的屬性 : " + toString());
        }

        public Memento createMemento() {//創(chuàng)建備忘錄,即游戲存檔
            Memento memento = new Memento();
            memento.setLevel(mLevel);
            memento.setCoin(mCoin);
            return memento;
        }

        public void setMemento(Memento memento) {
            mLevel = memento.getLevel();
            mCoin = memento.getCoin();
            System.out.println("讀取存檔信息:" + toString());
        }
    }
4.2 創(chuàng)建備忘錄角色

負(fù)責(zé)將游戲類的內(nèi)部狀態(tài)存儲(chǔ)起來(lái):

    public class Memento {//備忘錄類
        public int level;//等級(jí)
        public int coin;//金幣數(shù)量

        public void setLevel(int level) {
            this.level = level;
        }

        public void setCoin(int coin) {
            this.coin = coin;
        }

        public int getLevel() {
            return level;
        }

        public int getCoin() {
            return coin;
        }
    }
4.3 創(chuàng)建負(fù)責(zé)人角色

負(fù)責(zé)保存?zhèn)渫?,不能?duì)備忘錄的內(nèi)容進(jìn)行操作和訪問(wèn),只能將備忘錄傳遞給其他對(duì)象。

     public class Caretaker {//備忘錄管理類
        private Memento mMemento;

        public void setMemento(Memento memento) {
            mMemento = memento;
        }

        public Memento getMemento() {
            return mMemento;
        }
    }
4.4 客戶端測(cè)試
     public void test() {
        System.out.println("首次進(jìn)入游戲");
        Game game = new Game();
        game.play();//玩游戲
        Memento memento = game.createMemento();//創(chuàng)建存檔
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(memento);//保存存檔
        game.exit();//退出游戲

        System.out.println("-------------");
        System.out.println("二次進(jìn)入游戲");
        Game secondGame = new Game();
        secondGame.setMemento(caretaker.getMemento());//讀取存檔
        secondGame.play();//繼續(xù)玩游戲
        secondGame.exit();//不存檔,嘿嘿嘿

    }
輸出結(jié)果:
   首次進(jìn)入游戲
   升級(jí)了
   當(dāng)前等級(jí)為:2
   獲得金幣:32
   當(dāng)前金幣數(shù)量為:32
   退出游戲
   退出游戲時(shí)的屬性 : game{mLevel=2, mCoin=32}
   -------------
   二次進(jìn)入游戲
   讀取存檔信息:game{mLevel=2, mCoin=32}
   升級(jí)了
   當(dāng)前等級(jí)為:3
   獲得金幣:32
   當(dāng)前金幣數(shù)量為:64
   退出游戲
   退出游戲時(shí)的屬性 : game{mLevel=3, mCoin=64}

5. 應(yīng)用場(chǎng)景

  • 需要保存對(duì)象的某一時(shí)刻的狀態(tài)時(shí)

6. 優(yōu)點(diǎn)

  • 能夠讓狀態(tài)回滾到某一時(shí)刻的狀態(tài)
  • 實(shí)現(xiàn)了狀態(tài)保存對(duì)象的封裝,用戶無(wú)需關(guān)心其實(shí)現(xiàn)細(xì)節(jié)。

7. 缺點(diǎn)

  • 要保存的對(duì)象如果成員變量過(guò)多的話,資源消耗也會(huì)相應(yīng)增多。

8. Android中的源碼分析

Android中的Activity就提供了狀態(tài)保存機(jī)制來(lái)保證Activity在被系統(tǒng)回收后能夠恢復(fù)當(dāng)前Activity的數(shù)據(jù)。這一機(jī)制實(shí)際上就是onSaveInstanceStateonRestoreInstanceState。onSaveInstanceState就是用來(lái)保存當(dāng)前Activity的狀態(tài),onRestoreInstanceState則是用來(lái)恢復(fù)Activity的狀態(tài)。

8.1 onSaveInstanceState 源碼

    protected void onSaveInstanceState(Bundle outState) {//保存各種狀態(tài)

        //1.保存Activity對(duì)應(yīng)Window的狀態(tài)信息
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());

        //2.如果存在Fragments,則保存所有Fragments的狀態(tài)信息
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }

        //3.如果設(shè)置了ActivityLifecycleCallbacks回調(diào),那么會(huì)調(diào)用ActivityLifecycleCallbacks的onSaveInstanceState來(lái)進(jìn)行保存狀態(tài)信息
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

8.2 onRestoreInstanceState 源碼

   protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mWindow != null) {
            //獲取保存過(guò)的window狀態(tài)信息
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            //如果存在狀態(tài)信息,則window進(jìn)行恢復(fù)
            if (windowState != null) {
                mWindow.restoreHierarchyState(windowState);
            }
        }
    }

8.3 總結(jié)

  • Activity的狀態(tài)保存與恢復(fù)其實(shí)是個(gè)比較復(fù)雜的東西,很多細(xì)節(jié)這里都沒(méi)說(shuō)到,有興趣的同學(xué)可以找相關(guān)資料研究下,這里主要還是講設(shè)計(jì)模式在Android源碼中的應(yīng)用。
  • 在上面的源碼中,Activity實(shí)際上就是負(fù)責(zé)人角色(Caretaker),負(fù)責(zé)保存和恢復(fù)UI信息;Activity、View、ViewGroup、Fragment等都是發(fā)起人角色(Originator),他們各自負(fù)責(zé)需要保存的信息;而備忘錄角色(Memoto)則是Bundle類了,相關(guān)狀態(tài)信息都是保存在Bundle中。
  • 此外,Canvas中的Save()Restore()也是使用到了備忘錄模式,有興趣的可以去看下。

相關(guān)文章閱讀
Android的設(shè)計(jì)模式-設(shè)計(jì)模式的六大原則
一句話總結(jié)23種設(shè)計(jì)模式則
創(chuàng)建型模式:
Android的設(shè)計(jì)模式-單例模式
Android的設(shè)計(jì)模式-建造者模式
Android的設(shè)計(jì)模式-工廠方法模式
Android的設(shè)計(jì)模式-簡(jiǎn)單工廠模式
Android的設(shè)計(jì)模式-抽象工廠模式
Android的設(shè)計(jì)模式-原型模式
行為型模式:
Android的設(shè)計(jì)模式-策略模式
Android的設(shè)計(jì)模式-狀態(tài)模式
Android的設(shè)計(jì)模式-責(zé)任鏈模式
Android的設(shè)計(jì)模式-觀察者模式
Android的設(shè)計(jì)模式-模板方法模式
Android的設(shè)計(jì)模式-迭代器模式
Android的設(shè)計(jì)模式-備忘錄模式
Android的設(shè)計(jì)模式-訪問(wèn)者模式
Android的設(shè)計(jì)模式-中介者模式
Android的設(shè)計(jì)模式-解釋器模式
Android的設(shè)計(jì)模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計(jì)模式-代理模式
Android的設(shè)計(jì)模式-組合模式
Android的設(shè)計(jì)模式-適配器模式
Android的設(shè)計(jì)模式-裝飾者模式
Android的設(shè)計(jì)模式-享元模式
Android的設(shè)計(jì)模式-外觀模式
Android的設(shè)計(jì)模式-橋接模式

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

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