設(shè)計(jì)模式學(xué)習(xí)筆記(14)備忘錄

本文實(shí)例代碼:https://github.com/JamesZBL/java_design_patterns

備忘錄模式(Memento),別名為快照模式(Snapshot)蟀苛,是的行為型模式的一種召边。它的主要特點(diǎn)是創(chuàng)建一個(gè)特殊對(duì)象用于保存其他若干個(gè)對(duì)象在某一刻的狀態(tài),以便在需要獲得該狀態(tài)的時(shí)候能夠及時(shí)恢復(fù)汰蜘。

實(shí)例

一粒種子從被播種到發(fā)芽再到開花會(huì)經(jīng)歷很長(zhǎng)的時(shí)間灼狰,雖然我們用肉眼看不出來它在長(zhǎng)大掩幢,但它的確每時(shí)每刻都在生長(zhǎng)或油。植物生長(zhǎng)過程中的每一刻的狀態(tài)都是不完全相同的寞忿,所以我們可以用一個(gè)“快照”來保存植物的若干個(gè)狀態(tài)。

我們暫時(shí)不考慮植物學(xué)上各種微觀的狀態(tài)顶岸,所以簡(jiǎn)單定義一下植物腔彰,它的狀態(tài)由高度和重量組成叫编,同時(shí),植物區(qū)分不同的生長(zhǎng)階段:

Plant.java


public interface Plant {

  int getWeight();

  int getHeight();

  FlowerType getType();

}

定義一個(gè)花朵類 Flower霹抛,它實(shí)現(xiàn)植物 Plant 接口宵溅,以獲得其生長(zhǎng)過程中某一時(shí)刻的狀態(tài),同時(shí)花朵可以生長(zhǎng)上炎,為了模擬生長(zhǎng)過程,我們自定義一個(gè)生長(zhǎng)速度計(jì)算公式雏搂,并且每次調(diào)用 growing 方法都會(huì)使花朵的階段向下移階段跳轉(zhuǎn)藕施,比如花朵處于種子階段的時(shí)候,生長(zhǎng)一次就處于了 “花苞” 的階段凸郑。

模擬花朵生長(zhǎng)的方法:


public void growing() {

  setWeight(getWeight() * 2);

  setHeight(getHeight() * 3);

  switch (type) {

    case SEED: {

      setType(FlowerType.BURGEON);

      break;

    }

    case BURGEON: {

      setType(FlowerType.BUD);

      break;

    }

    case BUD: {

      setType(FlowerType.BLOOM);

      break;

    }

    case BLOOM: {

      setType(FlowerType.DEAD);

      setHeight(0);

      setWeight(0);

      break;

    }

    default:

      break;

  }

}

在花朵類中定義一個(gè)私有的靜態(tài)內(nèi)部類 FlowerMemento裳食,這個(gè)類負(fù)責(zé)記錄花朵的生長(zhǎng)狀態(tài):


private static class FlowerMemento implements Plant {

  private FlowerType type;

  private int height;

  private int weight;

  private FlowerMemento(FlowerType type, int height, int weight) {

    this.type = type;

    this.height = height;

    this.weight = weight;

  }

  @Override

  public int getWeight() {

    return weight;

  }

  @Override

  public int getHeight() {

    return height;

  }

  @Override

  public FlowerType getType() {

    return type;

  }

}

用一個(gè)枚舉類來定義花朵的生長(zhǎng)階段:

FlowerType.java


public enum FlowerType {

  SEED("種子"), BURGEON("發(fā)芽"), BUD("花苞"), BLOOM("開放"), DEAD("凋零");

  private String name;

  FlowerType(String name) {

    this.name = name;

  }

  @Override

  public String toString() {

    return name;

  }

}

為了便于理清這幾個(gè)類之間的關(guān)系,現(xiàn)在給出完整的 Flower 類:

Flower.java


public class Flower implements Plant {

  private FlowerType type;

  private final String name;

  private int height;

  private int weight;

  public void growing() {

    // 上文給出了完整的此方法

  }

  FlowerMemento getMemento() {

    return new FlowerMemento(getType(), getHeight(), getWeight());

  }

  void setMemento(Plant plant) {

    FlowerMemento flowerMemento = (FlowerMemento) plant;

    setType(flowerMemento.getType());

    setHeight(flowerMemento.getHeight());

    setWeight(flowerMemento.getWeight());

  }

  @Override

  public String toString() {

    return String.format("名稱:%s\t狀態(tài):%s\t質(zhì)量:%d克\t高度:%d厘米", getName(), getType(), getWeight(), getHeight());

  }

  public Flower(FlowerType type, String name, int height, int weight) {

    this.type = type;

    this.name = name;

    this.height = height;

    this.weight = weight;

  }

  // getter & setter ...

  private static class FlowerMemento implements Plant {

    private FlowerType type;

    private int height;

    private int weight;

    private FlowerMemento(FlowerType type, int height, int weight) {

      this.type = type;

      this.height = height;

      this.weight = weight;

    }

    // getter & setter ...

  }

}

最后模擬一下花朵的生長(zhǎng)過程:

App.java


public class Application {

  private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);

  public static void main(String[] args) {

    Flower flower = new Flower(FlowerType.SEED, "水仙花", 1, 2);

    LOGGER.info(flower.toString());

    flower.growing();

    LOGGER.info(flower.toString());

    flower.growing();

    LOGGER.info(flower.toString());

    flower.growing();

    LOGGER.info(flower.toString());

    flower.growing();

    LOGGER.info(flower.toString());

    flower.growing();

    LOGGER.info(flower.toString());

  }

}

總結(jié)

通過這個(gè)例子可以總結(jié)出芙沥,備忘錄模式的主要特點(diǎn)有:

在不修改被捕獲對(duì)象的原有狀態(tài)前提下诲祸,抓取一個(gè)對(duì)象的內(nèi)部狀態(tài),并在獨(dú)立于該對(duì)象的對(duì)象中保存被捕獲對(duì)象的狀態(tài)而昨。所以應(yīng)該使用靜態(tài)內(nèi)部類作為快照保存的實(shí)現(xiàn)救氯,因?yàn)閷?duì)象的狀態(tài)和對(duì)象沒有直接緊密的聯(lián)系,而是相對(duì)的獨(dú)立聯(lián)系歌憨。

為了保證狀態(tài)持有者的數(shù)據(jù)不允許被除了 “被捕獲對(duì)象” 之外的對(duì)象訪問到着憨,應(yīng)當(dāng)將狀態(tài)持有者的類定義為 “被捕獲對(duì)象類” 的私有類。

在許多的軟件中务嫡,都需要保存當(dāng)前工作進(jìn)度的功能甲抖,所以這些正是備忘錄模式的使用場(chǎng)景:

  • 游戲軟件中的存檔

  • 字處理軟件(比如 MS Office)中 “撤銷上一步” 的操作

  • 瀏覽器中的返回上一頁

  • 數(shù)據(jù)庫(kù)中的事務(wù)回滾

為了避免每次保存狀態(tài)和恢復(fù)狀態(tài)耗費(fèi)較多內(nèi)存資源,可以將備忘錄模式和之前的文章中提到的原型模式結(jié)合使用心铃。

個(gè)人博客同步更新准谚,獲取更多技術(shù)分享請(qǐng)關(guān)注:鄭保樂的博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市去扣,隨后出現(xiàn)的幾起案子柱衔,更是在濱河造成了極大的恐慌,老刑警劉巖厅篓,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秀存,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡羽氮,警方通過查閱死者的電腦和手機(jī)或链,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來档押,“玉大人澳盐,你說我怎么就攤上這事祈纯。” “怎么了叼耙?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵腕窥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我筛婉,道長(zhǎng)簇爆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任爽撒,我火速辦了婚禮入蛆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘硕勿。我一直安慰自己哨毁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布源武。 她就那樣靜靜地躺著扼褪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粱栖。 梳的紋絲不亂的頭發(fā)上话浇,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音闹究,去河邊找鬼凳枝。 笑死,一個(gè)胖子當(dāng)著我的面吹牛跋核,可吹牛的內(nèi)容都是我干的岖瑰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼砂代,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蹋订!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刻伊,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤露戒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后捶箱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體智什,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年丁屎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荠锭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晨川,死狀恐怖证九,靈堂內(nèi)的尸體忽然破棺而出删豺,到底是詐尸還是另有隱情,我是刑警寧澤愧怜,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布呀页,位于F島的核電站,受9級(jí)特大地震影響拥坛,放射性物質(zhì)發(fā)生泄漏蓬蝶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一猜惋、第九天 我趴在偏房一處隱蔽的房頂上張望疾党。 院中可真熱鬧,春花似錦惨奕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至香罐,卻和暖如春卧波,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背庇茫。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工港粱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人旦签。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓查坪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宁炫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子偿曙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容