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

前言

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

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

1.定義

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

2.介紹

  • 備忘錄模式屬于行為型模式。
  • 備忘錄模式比較適合用于功能復雜刃唐,但是需要維護和紀錄歷史的地方羞迷,或者是需要保存一個或者多個屬性的地方界轩;在未來某個時刻需要時,將其還原到原來紀錄的狀態(tài)衔瓮。

3.UML類圖

備忘錄模式UML類圖.jpg
角色說明:
  • Originator(發(fā)起人角色):負責創(chuàng)建一個備忘錄(Memoto)浊猾,能夠記錄內(nèi)部狀態(tài),以及恢復原來記錄的狀態(tài)热鞍。并且能夠決定哪些狀態(tài)是需要備忘的葫慎。
  • Memoto(備忘錄角色):將發(fā)起人(Originator)對象的內(nèi)部狀態(tài)存儲起來;并且可以防止發(fā)起人(Originator)之外的對象訪問備忘錄(Memoto)碍现。
  • Caretaker(負責人角色):負責保存?zhèn)渫洠∕emoto)幅疼,不能對備忘錄(Memoto)的內(nèi)容進行操作和訪問,只能將備忘錄傳遞給其他對象昼接。

4.實現(xiàn)

以游戲存檔為例子:

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

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

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

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

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

        public void exit() {
            System.out.println("退出游戲");
            System.out.println("退出游戲時的屬性 : " + 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)建備忘錄角色

負責將游戲類的內(nèi)部狀態(tài)存儲起來:

    public class Memento {//備忘錄類
        public int level;//等級
        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)建負責人角色

負責保存?zhèn)渫洠荒軐渫浀膬?nèi)容進行操作和訪問慢睡,只能將備忘錄傳遞給其他對象逐工。

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

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

        public Memento getMemento() {
            return mMemento;
        }
    }
4.4 客戶端測試
     public void test() {
        System.out.println("首次進入游戲");
        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("二次進入游戲");
        Game secondGame = new Game();
        secondGame.setMemento(caretaker.getMemento());//讀取存檔
        secondGame.play();//繼續(xù)玩游戲
        secondGame.exit();//不存檔,嘿嘿嘿

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

5. 應用場景

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

6. 優(yōu)點

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

7. 缺點

  • 要保存的對象如果成員變量過多的話泪喊,資源消耗也會相應增多。

8. Android中的源碼分析

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

8.1 onSaveInstanceState 源碼

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

        //1.保存Activity對應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),那么會調(diào)用ActivityLifecycleCallbacks的onSaveInstanceState來進行保存狀態(tài)信息
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

8.2 onRestoreInstanceState 源碼

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

8.3 總結(jié)

  • Activity的狀態(tài)保存與恢復其實是個比較復雜的東西,很多細節(jié)這里都沒說到包各,有興趣的同學可以找相關(guān)資料研究下摘仅,這里主要還是講設(shè)計模式在Android源碼中的應用。
  • 在上面的源碼中问畅,Activity實際上就是負責人角色(Caretaker)娃属,負責保存和恢復UI信息;Activity护姆、View矾端、ViewGroupFragment等都是發(fā)起人角色(Originator)卵皂,他們各自負責需要保存的信息须床;而備忘錄角色(Memoto)則是Bundle類了,相關(guān)狀態(tài)信息都是保存在Bundle中渐裂。
  • 此外豺旬,Canvas中的Save()Restore()也是使用到了備忘錄模式,有興趣的可以去看下柒凉。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末族阅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子膝捞,更是在濱河造成了極大的恐慌坦刀,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔬咬,死亡現(xiàn)場離奇詭異鲤遥,居然都是意外死亡,警方通過查閱死者的電腦和手機林艘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門盖奈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狐援,你說我怎么就攤上這事钢坦。” “怎么了啥酱?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵爹凹,是天一觀的道長。 經(jīng)常有香客問我镶殷,道長禾酱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任绘趋,我火速辦了婚禮颤陶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埋心。我一直安慰自己指郁,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布拷呆。 她就那樣靜靜地躺著闲坎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茬斧。 梳的紋絲不亂的頭發(fā)上腰懂,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音项秉,去河邊找鬼绣溜。 笑死,一個胖子當著我的面吹牛娄蔼,可吹牛的內(nèi)容都是我干的怖喻。 我是一名探鬼主播底哗,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锚沸!你這毒婦竟也來了跋选?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤哗蜈,失蹤者是張志新(化名)和其女友劉穎前标,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體距潘,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡炼列,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了音比。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俭尖。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖硅确,靈堂內(nèi)的尸體忽然破棺而出目溉,到底是詐尸還是另有隱情,我是刑警寧澤菱农,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布缭付,位于F島的核電站,受9級特大地震影響循未,放射性物質(zhì)發(fā)生泄漏陷猫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一的妖、第九天 我趴在偏房一處隱蔽的房頂上張望绣檬。 院中可真熱鬧,春花似錦嫂粟、人聲如沸娇未。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽零抬。三九已至,卻和暖如春宽涌,著一層夾襖步出監(jiān)牢的瞬間平夜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工卸亮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留忽妒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像段直,于是被迫代替她去往敵國和親吃溅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359