1. 設(shè)計(jì)模式之單例模式

        共 4416字,需瀏覽 9分鐘

         ·

        2022-02-24 01:46

        單例模式的基本概念

        單例模式是一種保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)全局訪問點(diǎn)的設(shè)計(jì)模式,它還有些許其他的叫法,比如說懶漢模式、單子模式等。那么這種設(shè)計(jì)模式解決了一個(gè)什么事情呢?我們來看下這樣一段代碼

        function?Foo()?{}

        const?s1?=?new?Foo();
        const?s2?=?new?Foo();
        console.log(s1?===?s2);?//?false

        從結(jié)果上看,每通過構(gòu)造函數(shù)創(chuàng)建一個(gè)對象,就會(huì)新開辟一片內(nèi)存去存儲,所以兩個(gè)對象的值是不相等,而我們要做的事情是,讓它每次創(chuàng)建出來的結(jié)果都是同一個(gè),那這就是單例模式,運(yùn)用到現(xiàn)實(shí)生活中的場景,比如說全局狀態(tài)、前端頁面中的模態(tài)框等等。下面跟著單例模式的實(shí)現(xiàn),我們來一步一步地改造它。

        單例模式的實(shí)現(xiàn)

        隨著 ECMAScript 標(biāo)準(zhǔn)的更新?lián)Q代,最開始我們是通過函數(shù)+全局變量,或者函數(shù)加閉包的形式去實(shí)現(xiàn)單例模式,到后來 ES6 中有了 Class 的語法,我們可以用 Class 去寫單例,所以本文通過三種方式介紹單例模式的實(shí)現(xiàn)。

        全局變量 + 函數(shù)

        function?Singleton()?{}

        Singleton.getInstance?=?function?()?{
        ??if?(!window.instance)?{
        ????window.instance?=?new?Singleton();
        ??}
        ??return?window.instance;
        };

        const?s1?=?Singleton.getInstance();
        const?s2?=?Singleton.getInstance();
        console.log(s1?===?s2);?//?true

        這里思考下這樣寫有什么不好的嗎?有的。例如程序員李雷在全局變量上掛載了一個(gè) instance 屬性,程序員韓梅梅也在全局變量 windows 上掛載了一個(gè) instance 屬性。他們互相都不告訴對方自己在 windows 上掛載了一個(gè) instance 屬性,那么這個(gè)時(shí)候是不是就會(huì)產(chǎn)生沖突呢?所以這樣子寫,不好。

        函數(shù)+閉包

        function?Singleton()?{}

        Singleton.getInstance?=?(function?()?{
        ??let?instance?=?null;
        ??return?function?()?{
        ????if?(!instance)?{
        ??????instance?=?new?Singleton();
        ????}
        ????return?instance;
        ??};
        })();

        const?s1?=?Singleton.getInstance();
        const?s2?=?Singleton.getInstance();
        console.log(s1?===?s2);?//?true

        ES 中面向?qū)ο蟮?Class

        class?Singleton?{
        ??static?getInstance()?{
        ????if?(!Singleton.instance)?{
        ??????Singleton.instance?=?new?Singleton();
        ????}
        ????return?Singleton.instance;
        ??}
        }

        const?s1?=?Singleton.getInstance();
        const?s2?=?Singleton.getInstance();
        console.log(s1?===?s2);?//?true

        單例模式的應(yīng)用

        單例模式作為最簡單的設(shè)計(jì)模式之一,在軟件開發(fā)中應(yīng)用也很廣泛,下面筆者結(jié)合自己的經(jīng)歷,主要從前端和后端分別舉一個(gè)例子來介紹設(shè)計(jì)模式的應(yīng)用。

        單例模式在前端的應(yīng)用

        前面我們說了模態(tài)框,比如說,你頁面有個(gè)登錄按鈕,點(diǎn)擊后會(huì)彈出一個(gè)登錄框,這里每次點(diǎn)擊登錄都重新彈一個(gè)新的模態(tài)框,顯然是不必要的,因?yàn)樗麄儍?nèi)容是一樣的,所以我們期望把它緩存下來,核心代碼如下:

        class?Modal?{
        ??static?getInstance()?{
        ????if?(!Modal.instance)?{
        ??????Modal.instance?=?new?Modal();
        ??????Modal.instance.createElement();
        ????}
        ????return?Modal.instance;
        ??}

        ??createElement()?{
        ????this.div?=?document.createElement('div');
        ????this.div.id?=?'modal';
        ????this.div.innerHTML?=?'全局模態(tài)框';
        ????this.div.style.display?=?'none';
        ????document.body.appendChild(this.div);
        ??}

        ??open()?{
        ????this.div.style.display?=?'block';
        ??}

        ??close()?{
        ????this.div.style.display?=?'none';
        ??}
        }

        document.getElementById('BtnOpen').addEventListener('click',?()?=>?{
        ??const?modal?=?Modal.getInstance();
        ??modal.open();
        });

        document.getElementById('BtnClose').addEventListener('click',?()?=>?{
        ??const?modal?=?Modal.getInstance();
        ??modal.close();
        });

        具體的 demo 地址:https://zhengjiangtao.cn/show/design-mode/singleton.html

        單例模式在后端的應(yīng)用

        這個(gè)是筆者在通過 nodejs 做微信開發(fā)的時(shí)候,借助單例模式的思想優(yōu)化相關(guān)的業(yè)務(wù)代碼的實(shí)踐所得,就是不能每次前端這邊來一個(gè)請求,或者別的地方引用或者使用到封裝的微信接口 API,就重新創(chuàng)建一個(gè)新的,那么數(shù)據(jù)量上去了,這邊開銷是會(huì)很大的,比如百萬、千萬等等,所以我們期望把它緩存下來,然后用到直接取就好了。

        //?創(chuàng)建一個(gè)微信公眾號相關(guān)的API類
        class?WechatOfficalAccountApi?{
        ??constructor(appId,?appSecret,?token)?{
        ????//?code...
        ??}
        }

        //?單例模式的實(shí)現(xiàn)
        const?createWechatOfficalAccountApi?=?(function?(appId,?appSecret,?token)?{
        ??let?instance?=?null;
        ??return?function?()?{
        ????if?(!instance)?{
        ??????instance?=?new?WechatOfficalAccountApi(appId,?appSecret,?token);
        ????}
        ????return?instance;
        ??};
        })();

        考慮到微信公眾號的類另有用途,所以就沒有都封裝到類里面,而是單獨(dú)拋出一個(gè)函數(shù)去做這件事,大家想一下這樣寫好不好???是的,不好。問題就在于,比如說我創(chuàng)建了一個(gè)單例對象實(shí)例是去處理公眾號”江濤學(xué)編程“的相關(guān)業(yè)務(wù)的,后來迫于生計(jì),老板決定賣藝,又搞了個(gè)”江濤學(xué)音樂“,那么這個(gè)時(shí)候你這個(gè)單例就歇菜了,因?yàn)樗挥幸粋€(gè)實(shí)現(xiàn)例的全局訪問點(diǎn),而 appid 每個(gè)微信公眾號都是不同的。

        考慮到樓上這個(gè)場景,其實(shí)不能簡單地去像樓上去設(shè)計(jì)單例模式。我想到一個(gè)例子,就好比水產(chǎn)養(yǎng)殖這個(gè)專業(yè),海王他就知道,單純地在池子里養(yǎng)草魚,草魚會(huì)有點(diǎn)孤單,它會(huì)不會(huì)不快樂呢?它會(huì)不會(huì)絕食呢?于是它把龍蝦也放了進(jìn)來,這樣子至少顯得不那么孤單,可以聊聊天,龍蝦你今天吃什么?草魚你今天吃什么?池子里充滿了歡聲笑語,哦,我明白了,我也給咱微信 API 接口造一個(gè)池子,開干。

        //?創(chuàng)建一個(gè)連接池
        const?wechatOfficalAccountApiPool?=?{};

        //?創(chuàng)建一個(gè)微信公眾號相關(guān)的API類
        class?WechatOfficalAccountApi?{
        ??constructor(appId,?appSecret,?token)?{
        ????//?code...
        ??}
        }

        //?單例模式的實(shí)現(xiàn)
        function?createWechatOfficalAccountApi(appId,?appSecret,?token)?{
        ??let?instance?=?wechatOfficalAccountApiPool[appId];
        ??if?(!instance)?{
        ????instance?=?new?WechatOfficalAccountApi(appId,?appSecret,?token);
        ????wechatOfficalAccountApiPool[appId]?=?instance;
        ??}
        ??if?(instance.appSecret?!==?appSecret?||?instance.token?!==?token)?{
        ????throw?new?Error(
        ??????`createWechatOfficalAccountApi(${appId},?${appSecret},?${token}):?`?+
        ????????`conflict?with?existing?one:?(${instance.appId},?${instance.appSecret},?${instance.token})`
        ????);
        ??}
        ??return?instance;
        }

        為了更健壯魯棒一點(diǎn),我們已知微信的 appid 是唯一的,就以它作為 key 來搞,這樣子的話就可以處理多個(gè)業(yè)務(wù)場景了,比如老板開了好多個(gè)媒體號,有“江濤學(xué)編程”,”江濤學(xué)音樂“,”江濤去旅行“等等,根據(jù)不同的業(yè)務(wù)場景和用途,就可以在最基礎(chǔ)的通用性強(qiáng)的微信接口 API 上去擴(kuò)展實(shí)現(xiàn)對應(yīng)的業(yè)務(wù)場景的功能。

        參考文獻(xiàn)

        • 維基百科 - 設(shè)計(jì)模式:https://zh.wikipedia.org/wiki/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F

        原文地址:https://zhengjiangtao.cn/coding/singleton.html


        瀏覽 43
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 成人性生交大片免费看黄106季 | 超碰操操操 | 色噜噜狠狠色综合影视 | 韩国无码一区二区三区 | 在线观看欧美三级 |