<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 4416字,需瀏覽 9分鐘

           ·

          2022-02-24 01:46

          單例模式的基本概念

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

          function?Foo()?{}

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

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

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

          隨著 ECMAScript 標(biāo)準(zhǔn)的更新?lián)Q代,最開(kāi)始我們是通過(guò)函數(shù)+全局變量,或者函數(shù)加閉包的形式去實(shí)現(xiàn)單例模式,到后來(lái) ES6 中有了 Class 的語(yǔ)法,我們可以用 Class 去寫單例,所以本文通過(guò)三種方式介紹單例模式的實(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 屬性。他們互相都不告訴對(duì)方自己在 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)用

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

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

          前面我們說(shuō)了模態(tài)框,比如說(shuō),你頁(yè)面有個(gè)登錄按鈕,點(diǎn)擊后會(huì)彈出一個(gè)登錄框,這里每次點(diǎn)擊登錄都重新彈一個(gè)新的模態(tài)框,顯然是不必要的,因?yàn)樗麄儍?nèi)容是一樣的,所以我們期望把它緩存下來(lá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è)是筆者在通過(guò) nodejs 做微信開(kāi)發(fā)的時(shí)候,借助單例模式的思想優(yōu)化相關(guān)的業(yè)務(wù)代碼的實(shí)踐所得,就是不能每次前端這邊來(lái)一個(gè)請(qǐng)求,或者別的地方引用或者使用到封裝的微信接口 API,就重新創(chuàng)建一個(gè)新的,那么數(shù)據(jù)量上去了,這邊開(kāi)銷是會(huì)很大的,比如百萬(wàn)、千萬(wàn)等等,所以我們期望把它緩存下來(lái),然后用到直接取就好了。

          //?創(chuàng)建一個(gè)微信公眾號(hào)相關(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;
          ??};
          })();

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

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

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

          //?創(chuàng)建一個(gè)微信公眾號(hào)相關(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 來(lái)搞,這樣子的話就可以處理多個(gè)業(yè)務(wù)場(chǎng)景了,比如老板開(kāi)了好多個(gè)媒體號(hào),有“江濤學(xué)編程”,”江濤學(xué)音樂(lè)“,”江濤去旅行“等等,根據(jù)不同的業(yè)務(wù)場(chǎng)景和用途,就可以在最基礎(chǔ)的通用性強(qiáng)的微信接口 API 上去擴(kuò)展實(shí)現(xiàn)對(duì)應(yīng)的業(yè)務(wù)場(chǎng)景的功能。

          參考文獻(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)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品79色在线 | 国产精品99久久久久久人 | 欧美黑人大群交舔舔舔 | 亚洲sv视频 | 嫩苞又嫩又紧AV无码 |