小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)備忘錄模式「模擬互聯(lián)網(wǎng)系統(tǒng)上線過程中,配置文件回滾場景」

 小傅哥 2021-12-13


作者:小傅哥
博客:https:// - 原創(chuàng)系列專題文章

沉淀、分享、成長,讓自己和他人都能有所收獲!😄

一、前言

實(shí)現(xiàn)不了是研發(fā)的借口?

實(shí)現(xiàn)不了,有時(shí)候是功能復(fù)雜度較高難以實(shí)現(xiàn),有時(shí)候是工期較短實(shí)現(xiàn)不完。而編碼的行為又是一個(gè)不太好量化的過程,同樣一個(gè)功能每個(gè)人的實(shí)現(xiàn)方式不一樣,遇到開發(fā)問題解決問題的速度也不一樣。除此之外還很不好給產(chǎn)品解釋具體為什么要這個(gè)工期時(shí)間,這就像蓋樓的圖紙最終要多少水泥砂漿一樣。那么這時(shí)研發(fā)會(huì)盡可能的去通過一些經(jīng)驗(yàn),制定流程規(guī)范、設(shè)計(jì)、開發(fā)、評審等,確定一個(gè)可以完成的時(shí)間范圍,又避免風(fēng)險(xiǎn)的時(shí)間點(diǎn)后。再被壓縮,往往會(huì)出一些矛盾點(diǎn),能壓縮要解釋為什么之前要那么多時(shí)間,不能壓縮又有各方不斷施加的壓力。因此有時(shí)候不一定是借口,是要考慮如何讓整個(gè)團(tuán)隊(duì)健康的發(fā)展。

鼓勵(lì)有時(shí)比壓力要重要!

在學(xué)習(xí)的過程中,很多時(shí)候我們聽到的都是,你要怎樣,怎樣,你瞧瞧誰誰誰,哪怕今天聽不到這樣的聲音了,但因?yàn)樵?jīng)反復(fù)聽到過而導(dǎo)致內(nèi)心抗拒。雖然也知道自己要去學(xué),但是很難堅(jiān)持,學(xué)著學(xué)著就沒有了方向,看到還有那么多不會(huì)的就更慌了,以至于最后心態(tài)崩了,更不愿意學(xué)。其實(shí)程序員的壓力并不小,想成長幾乎是需要一直的學(xué)習(xí),就像似乎再也不敢說精通java了一樣,知識量實(shí)在是隨著學(xué)習(xí)的深入,越來越深,越來越廣。所以需要,開心學(xué)習(xí),快樂成長!

臨陣的你好像一直很著急!

經(jīng)常的聽到;老師明天就要了你幫我弄弄吧你給我寫一下完事我就學(xué)這次著急、現(xiàn)在這不是沒時(shí)間學(xué)嗎快給我看看。其實(shí)看到的類似的還有很多,很納悶?zāi)愕闹痹趺磥淼?#xff0c;不太可能,人在家中坐,禍從天上落。老師怎么就那個(gè)時(shí)間找你了,老板怎么就今天管你要了,還不是日積月累你沒有學(xué)習(xí),臨時(shí)抱佛腳亂著急!即使后來真的有人幫你了,但最好不要放松,要盡快學(xué)會(huì),躲得過初一還有初二呢!

二、開發(fā)環(huán)境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程一個(gè),可以通過關(guān)注公眾號bugstack蟲洞棧,回復(fù)源碼下載獲取(打開獲取的鏈接,找到序號18)
工程描述
itstack-demo-design-17-00開發(fā)配置文件備忘錄

三、備忘錄模式介紹

備忘錄模式,圖片來自 refactoringguru.cn

備忘錄模式是以可以恢復(fù)或者說回滾,配置、版本、悔棋為核心功能的設(shè)計(jì)模式,而這種設(shè)計(jì)模式屬于行為模式。在功能實(shí)現(xiàn)上是以不破壞原對象為基礎(chǔ)增加備忘錄操作類,記錄原對象的行為從而實(shí)現(xiàn)備忘錄模式。

這個(gè)設(shè)計(jì)在我們平常的生活或者開發(fā)中也是比較常見的,比如:后悔藥、孟婆湯(一下回滾到0),IDEA編輯和撤銷、小霸王游戲機(jī)存檔。當(dāng)然還有我們非常常見的Photoshop,如下;

Photoshop 歷史記錄

四、案例場景模擬

場景模擬;系統(tǒng)發(fā)布上線配置回滾

在本案例中我們模擬系統(tǒng)在發(fā)布上線的過程中記錄線上配置文件用于緊急回滾

在大型互聯(lián)網(wǎng)公司系統(tǒng)的發(fā)布上線一定是易用、安全、可處理緊急狀況的,同時(shí)為了可以隔離線上和本地環(huán)境,一般會(huì)把配置文件抽取出來放到線上,避免有人誤操作導(dǎo)致本地的配置內(nèi)容發(fā)布出去。同時(shí)線上的配置文件也會(huì)在每次變更的時(shí)候進(jìn)行記錄,包括;版本號、時(shí)間、MD5、內(nèi)容信息和操作人。

在后續(xù)上線時(shí)如果發(fā)現(xiàn)緊急問題,系統(tǒng)就會(huì)需要回滾操作,如果執(zhí)行回滾那么也可以設(shè)置配置文件是否回滾。因?yàn)槊恳粋€(gè)版本的系統(tǒng)可能會(huì)隨著帶著一些配置文件的信息,這個(gè)時(shí)候就可以很方便的讓系統(tǒng)與配置文件一起回滾操作。

我們接下來就使用備忘錄模式,模擬如何記錄配置文件信息。實(shí)際的使用過程中還會(huì)將信息存放到庫中進(jìn)行保存,這里暫時(shí)只是使用內(nèi)存記錄。

五、備忘錄模式記錄配置文件版本信息

備忘錄的設(shè)計(jì)模式實(shí)現(xiàn)方式,重點(diǎn)在于不更改原有類的基礎(chǔ)上,增加備忘錄類存放記錄??赡芷綍r(shí)雖然不一定非得按照這個(gè)設(shè)計(jì)模式的代碼結(jié)構(gòu)來實(shí)現(xiàn)自己的需求,但是對于功能上可能也完成過類似的功能,記錄系統(tǒng)的信息。

除了現(xiàn)在的這個(gè)案例外,還可以是運(yùn)營人員在后臺(tái)erp創(chuàng)建活動(dòng)對信息的記錄,方便運(yùn)營人員可以上下修改自己的版本,而不至于因?yàn)檎`操作而丟失信息。

1. 工程結(jié)構(gòu)

itstack-demo-design-17-00
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.design
    │           ├── Admin.java
    │           ├── ConfigFile.java
    │           ├── ConfigMemento.java
    │           └── ConfigOriginator.java
    └── test
        └── java
            └── org.itstack.demo.design.test
                └── ApiTest.java

備忘錄模式模型結(jié)構(gòu)

備忘錄模式模型結(jié)構(gòu)

  • 以上是工程結(jié)構(gòu)的一個(gè)類圖,其實(shí)相對來說并不復(fù)雜,除了原有的配置類(ConfigFile)以外,只新增加了三個(gè)類。
  • ConfigMemento:備忘錄類,相當(dāng)于是對原有配置類的擴(kuò)展
  • ConfigOriginator:記錄者類,獲取和返回備忘錄類對象信息
  • Admin:管理員類,用于操作記錄備忘信息,比如你一些列的順序執(zhí)行了什么或者某個(gè)版本下的內(nèi)容信息

2. 代碼實(shí)現(xiàn)

2.1 配置信息類

public class ConfigFile {

    private String versionNo; // 版本號
    private String content;   // 內(nèi)容
    private Date dateTime;    // 時(shí)間
    private String operator;  // 操作人
    
    // ...get/set
}
  • 配置類可以是任何形式的,這里只是簡單的描述了一個(gè)基本的配置內(nèi)容信息。

2.2 備忘錄類

public class ConfigMemento {

    private ConfigFile configFile;

    public ConfigMemento(ConfigFile configFile) {
        this.configFile = configFile;
    }

    public ConfigFile getConfigFile() {
        return configFile;
    }

    public void setConfigFile(ConfigFile configFile) {
        this.configFile = configFile;
    }
    
}
  • 備忘錄是對原有配置類的擴(kuò)展,可以設(shè)置和獲取配置信息。

2.3 記錄者類

public class ConfigOriginator {

    private ConfigFile configFile;

    public ConfigFile getConfigFile() {
        return configFile;
    }

    public void setConfigFile(ConfigFile configFile) {
        this.configFile = configFile;
    }

    public ConfigMemento saveMemento(){
        return new ConfigMemento(configFile);
    }

    public void getMemento(ConfigMemento memento){
        this.configFile = memento.getConfigFile();
    }

}
  • 記錄者類除了對ConfigFile配置類增加了獲取和設(shè)置方法外,還增加了保存saveMemento()、獲取getMemento(ConfigMemento memento)。
  • saveMemento:保存?zhèn)渫浀臅r(shí)候會(huì)創(chuàng)建一個(gè)備忘錄信息,并返回回去,交給管理者處理。
  • getMemento:獲取的之后并不是直接返回,而是把備忘錄的信息交給現(xiàn)在的配置文件this.configFile,這部分需要注意。

2.4 管理員類

public class Admin {

    private int cursorIdx = 0;
    private List<ConfigMemento> mementoList = new ArrayList<ConfigMemento>();
    private Map<String, ConfigMemento> mementoMap = new ConcurrentHashMap<String, ConfigMemento>();

    public void append(ConfigMemento memento) {
        mementoList.add(memento);
        mementoMap.put(memento.getConfigFile().getVersionNo(), memento);
        cursorIdx++;
    }

    public ConfigMemento undo() {
        if (--cursorIdx <= 0) return mementoList.get(0);
        return mementoList.get(cursorIdx);
    }

    public ConfigMemento redo() {
        if (++cursorIdx > mementoList.size()) return mementoList.get(mementoList.size() - 1);
        return mementoList.get(cursorIdx);
    }

    public ConfigMemento get(String versionNo){
        return mementoMap.get(versionNo);
    }

}
  • 在這個(gè)類中主要實(shí)現(xiàn)的核心功能就是記錄配置文件信息,也就是備忘錄的效果,之后提供可以回滾和獲取的方法,拿到備忘錄的具體內(nèi)容。
  • 同時(shí)這里設(shè)置了兩個(gè)數(shù)據(jù)結(jié)構(gòu)來存放備忘錄,實(shí)際使用中可以按需設(shè)置。List<ConfigMemento>、Map<String, ConfigMemento>
  • 最后是提供的備忘錄操作方法;存放(append)、回滾(undo)、返回(redo)、定向獲取(get),這樣四個(gè)操作方法。

3. 測試驗(yàn)證

3.1 編寫測試類

@Test
public void test() {
    Admin admin = new Admin();
    ConfigOriginator configOriginator = new ConfigOriginator();
    configOriginator.setConfigFile(new ConfigFile("1000001", "配置內(nèi)容A=哈哈", new Date(), "小傅哥"));
    admin.append(configOriginator.saveMemento()); // 保存配置
    configOriginator.setConfigFile(new ConfigFile("1000002", "配置內(nèi)容A=嘻嘻", new Date(), "小傅哥"));
    admin.append(configOriginator.saveMemento()); // 保存配置
    configOriginator.setConfigFile(new ConfigFile("1000003", "配置內(nèi)容A=么么", new Date(), "小傅哥"));
    admin.append(configOriginator.saveMemento()); // 保存配置
    configOriginator.setConfigFile(new ConfigFile("1000004", "配置內(nèi)容A=嘿嘿", new Date(), "小傅哥"));
    admin.append(configOriginator.saveMemento()); // 保存配置  

    // 歷史配置(回滾)
    configOriginator.getMemento(admin.undo());
    logger.info("歷史配置(回滾)undo:{}", JSON.toJSONString(configOriginator.getConfigFile()));  

    // 歷史配置(回滾)
    configOriginator.getMemento(admin.undo());
    logger.info("歷史配置(回滾)undo:{}", JSON.toJSONString(configOriginator.getConfigFile()));  

    // 歷史配置(前進(jìn))
    configOriginator.getMemento(admin.redo());
    logger.info("歷史配置(前進(jìn))redo:{}", JSON.toJSONString(configOriginator.getConfigFile()));   

    // 歷史配置(獲取)
    configOriginator.getMemento(admin.get("1000002"));
    logger.info("歷史配置(獲取)get:{}", JSON.toJSONString(configOriginator.getConfigFile()));
}
  • 這個(gè)設(shè)計(jì)模式的學(xué)習(xí)有一部分重點(diǎn)是體現(xiàn)在了單元測試類上,這里包括了四次的信息存儲(chǔ)和備忘錄歷史配置操作。
  • 通過上面添加了四次配置后,下面分別進(jìn)行操作是;回滾1次、再回滾1次之后向前進(jìn)1次最后是獲取指定的版本配置。具體的效果可以參考測試結(jié)果。

3.2 測試結(jié)果

23:12:09.512 [main] INFO  org.itstack.demo.design.test.ApiTest - 歷史配置(回滾)undo:{"content":"配置內(nèi)容A=嘿嘿","dateTime":159209829432,"operator":"小傅哥","versionNo":"1000004"}
23:12:09.514 [main] INFO  org.itstack.demo.design.test.ApiTest - 歷史配置(回滾)undo:{"content":"配置內(nèi)容A=么么","dateTime":159209829432,"operator":"小傅哥","versionNo":"1000003"}
23:12:09.514 [main] INFO  org.itstack.demo.design.test.ApiTest - 歷史配置(前進(jìn))redo:{"content":"配置內(nèi)容A=嘿嘿","dateTime":159209829432,"operator":"小傅哥","versionNo":"1000004"}
23:12:09.514 [main] INFO  org.itstack.demo.design.test.ApiTest - 歷史配置(獲取)get:{"content":"配置內(nèi)容A=嘻嘻","dateTime":159320989432,"operator":"小傅哥","versionNo":"1000002"}

Process finished with exit code 0
  • 從測試效果上可以看到,歷史配置按照我們的指令進(jìn)行了回滾和前進(jìn),以及最終通過指定的版本進(jìn)行獲取,符合預(yù)期結(jié)果。

六、總結(jié)

  • 此種設(shè)計(jì)模式的方式可以滿足在不破壞原有屬性類的基礎(chǔ)上,擴(kuò)充了備忘錄的功能。雖然和我們平時(shí)使用的思路是一樣的,但在具體實(shí)現(xiàn)上還可以細(xì)細(xì)品味,這樣的方式在一些源碼中也有所體現(xiàn)。
  • 在以上的實(shí)現(xiàn)中我們是將配置模擬存放到內(nèi)存中,如果關(guān)機(jī)了會(huì)導(dǎo)致配置信息丟失,因?yàn)樵谝恍┱鎸?shí)的場景里還是需要存放到數(shù)據(jù)庫中。那么此種存放到內(nèi)存中進(jìn)行回復(fù)的場景也不是沒有,比如;Photoshop、運(yùn)營人員操作ERP配置活動(dòng),那么也就是即時(shí)性的一般不需要存放到庫中進(jìn)行恢復(fù)。另外如果是使用內(nèi)存方式存放備忘錄,需要考慮存儲(chǔ)問題,避免造成內(nèi)存大量消耗。
  • 設(shè)計(jì)模式的學(xué)習(xí)都是為了更好的寫出可擴(kuò)展、可管理、易維護(hù)的代碼,而這個(gè)學(xué)習(xí)的過程需要自己不斷的嘗試實(shí)際操作,理論的知識與實(shí)際結(jié)合還有很長一段距離。切記多多上手!

七、推薦閱讀

  • 1. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)工廠方法模式「多種類型商品不同接口,統(tǒng)一發(fā)獎(jiǎng)服務(wù)搭建場景」
  • 2. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)原型模式「上機(jī)考試多套試,每人題目和答案亂序排列場景」
  • 3. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)橋接模式「多支付渠道(微信、支付寶)與多支付模式(刷臉、指紋)場景」
  • 4. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)組合模式「營銷差異化人群發(fā)券,決策樹引擎搭建場景」
  • 5. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)外觀模式「基于SpringBoot開發(fā)門面模式中間件,統(tǒng)一控制接口白名單場景」
  • 6. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)享元模式「基于Redis秒殺,提供活動(dòng)與庫存信息查詢場景」
  • 7. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)備忘錄模式「模擬互聯(lián)網(wǎng)系統(tǒng)上線過程中,配置文件回滾場景」

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多