設(shè)計(jì)模式之享元模式(十八)

??以前想騎自行車(chē)需要去自行車(chē)店里購(gòu)買(mǎi),才能騎自行車(chē)?,F(xiàn)在有了共享單車(chē),我們則不需要購(gòu)買(mǎi)單車(chē),只需要掃描二維碼就可以來(lái)一場(chǎng)說(shuō)走就走的短途。共享單車(chē)的這種模式,我們可以理解為享元模式。

一、享元模式的定義

??所謂享元模式就是運(yùn)行共享技術(shù)有效地支持大量細(xì)粒度(對(duì)象的相似度比較高的屬性)對(duì)象的復(fù)用。系統(tǒng)使用少量對(duì)象,而且這些對(duì)象都比較相似,狀態(tài)變化小,可以實(shí)現(xiàn)對(duì)象的多次復(fù)用。


二、享元模式類(lèi)圖


三、享元模式的角色

  • Flyweight
    抽象享元類(lèi)。所有具體享元類(lèi)的超類(lèi)或者接口。Flyweight可以接受并作用于外部狀態(tài)。

  • ConcreteFlyweight
    具體享元類(lèi)。指定內(nèi)部狀態(tài),為內(nèi)部狀態(tài)增加存儲(chǔ)空間。

  • UnsharedConcreteFlyweight
    非共享具體享元類(lèi)。指出那些不需要共享的Flyweight子類(lèi)。

  • FlyweightFactory
    享元工廠(chǎng)類(lèi)。用來(lái)創(chuàng)建并管理Flyweight對(duì)象,它主要用來(lái)確保合理地共享Flyweight,當(dāng)用戶(hù)請(qǐng)求一個(gè)Flyweight時(shí),F(xiàn)lyweightFactory就會(huì)提供一個(gè)已經(jīng)創(chuàng)建的Flyweight對(duì)象或者新建一個(gè)(如果不存在)。


四、情景代碼

小明、小王、小李三個(gè)人要騎自行車(chē),接下來(lái)我們用代碼來(lái)實(shí)現(xiàn)。

  • 自行車(chē)類(lèi)
public class Bicycle {

private  String name;

public Bicycle (String name) {
    this.name = name;
}

public void  rideBicycle () {
    System.out.println(name+" 騎自行車(chē)");
}

}
  • 測(cè)試類(lèi)
public static void main(String[] args) {
    Bicycle bicycle1 = new Bicycle("小明");
    bicycle1.rideBicycle();

    Bicycle bicycle2 = new Bicycle("小王");
    bicycle2.rideBicycle();

    Bicycle bicycle3 = new Bicycle("小李");
    bicycle3.rideBicycle();
}

??通過(guò)上面的例子,我們可以看出,誰(shuí)要騎車(chē)都需要?jiǎng)?chuàng)建一個(gè)對(duì)象,對(duì)象都是相同的,這樣對(duì)內(nèi)存消耗是比較大的,而且也不符合設(shè)計(jì)模式編程。接下來(lái)我們用享元模式來(lái)實(shí)現(xiàn)。

  • 定義一個(gè)車(chē)類(lèi)的接口
public interface Car {
       public void  rideCar (String userName);
}
  • 非享元的實(shí)現(xiàn)類(lèi)
public class CarNoImpl implements Car {

@Override
public void rideCar(String userName) {
    System.out.println(userName+"騎單車(chē)");
}
}
  • 享元工廠(chǎng)類(lèi)
public class CarFactory {
      //  享元池
      //  如果找到了,不需要?jiǎng)?chuàng)建新的對(duì)象。包含了兩個(gè)意思,第一個(gè)意思:減少了對(duì)象的創(chuàng)建,第二個(gè),提高了對(duì)象的重復(fù)利用。
      private static Map<String,Object> filweighs = new HashMap<String,Object>();

      public Car getCar(String key,Car car) {
             if (!filweighs.containsKey(key)) {
                  filweighs.put(key, car);
             }
          return (Car) filweighs.get(key);
      }
}
  • 測(cè)試類(lèi)
public static void main(String[] args) {

   CarFactory carFactory = new CarFactory();
   Car car1 = carFactory.getCar("紅色",new CarNoImpl());
   car1.rideCar("小明");

   Car car2 = carFactory.getCar("藍(lán)色",new CarNoImpl());
   car2.rideCar("小王");

   Car car3 = carFactory.getCar("紅色",new CarNoImpl());
   car3.rideCar("小李");
}
  • 測(cè)試結(jié)果
 小明騎自行車(chē)
 小王騎自行車(chē)
 小李騎自行車(chē)

??小明、小李騎的是紅色的單車(chē),這時(shí)我們的享元工廠(chǎng)是通過(guò)顏色查找,如果集合中有這個(gè)對(duì)象,則不需要?jiǎng)?chuàng)建直接返回集合中的對(duì)象,如果沒(méi)有則需要?jiǎng)?chuàng)建對(duì)象,下次直接獲取享元池中的對(duì)象,這樣避免頻繁創(chuàng)建對(duì)象。

接下來(lái)我們來(lái)聊聊共享部分,也就是外部狀態(tài)。

  • 享元實(shí)現(xiàn)類(lèi)
public class CarOkImpl implements Car {

public Car car;

public CarOkImpl(Car car) {
    this.car = car;
}

@Override
public void rideCar(String userName) {
    if (null == car) {
        System.out.println("附近沒(méi)有單車(chē)可騎");
        return;
    }
    car.rideCar(userName);
}
}
  • 測(cè)試類(lèi)
public static void main(String[] args) {

   Car car4 = carFactory.getCar("黑色",new CarOkImpl(null));
   car4.rideCar("小王");

}
  • 測(cè)試結(jié)果
 附近沒(méi)有單車(chē)可騎

??測(cè)試我們發(fā)現(xiàn)非享元實(shí)現(xiàn)類(lèi)是不會(huì)改變內(nèi)部類(lèi)的狀態(tài),享元實(shí)現(xiàn)類(lèi)是通過(guò)客戶(hù)端可以改變內(nèi)部類(lèi)的狀態(tài)。
??這就是享元的模式的兩種狀態(tài),內(nèi)部狀態(tài)和外部狀態(tài)。
??內(nèi)部狀態(tài)存儲(chǔ)于享元對(duì)象內(nèi)部,而外部狀態(tài)則應(yīng)該由客戶(hù)端來(lái)考慮。


五、享元模式的優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn)

??1、享元模式的優(yōu)點(diǎn)在于它能夠極大的減少系統(tǒng)中對(duì)象的個(gè)數(shù)。
??2、享元模式由于使用了外部狀態(tài),外部狀態(tài)相對(duì)獨(dú)立,不會(huì)影響到內(nèi)部狀態(tài),所以享元模式使得享元對(duì)象能夠在不同的環(huán)境被共享。

  • 缺點(diǎn)

??1、由于享元模式需要區(qū)分外部狀態(tài)和內(nèi)部狀態(tài),使得應(yīng)用程序在某種程度上來(lái)說(shuō)更加復(fù)雜化了。
??2、為了使對(duì)象可以共享,享元模式需要將享元對(duì)象的狀態(tài)外部化,而讀取外部狀態(tài)使得運(yùn)行時(shí)間變長(zhǎng)。


六、適用場(chǎng)景

??如果一個(gè)系統(tǒng)中存在大量的相同或者相似的對(duì)象,由于這類(lèi)對(duì)象的大量使用,會(huì)造成系統(tǒng)內(nèi)存的耗費(fèi),可以使用享元模式來(lái)減少系統(tǒng)中對(duì)象的數(shù)量。
??對(duì)象的大部分狀態(tài)都可以外部化,可以將這些外部狀態(tài)傳入對(duì)象中。


七、小結(jié)

??享元模式可以極大地減少系統(tǒng)中對(duì)象的數(shù)量。但是它可能會(huì)引起系統(tǒng)的邏輯更加復(fù)雜化。享元模式的核心在于享元工廠(chǎng),它主要用來(lái)確保合理地共享對(duì)象。
??內(nèi)部狀態(tài)為不變共享部分,存儲(chǔ)于享元對(duì)象內(nèi)部,而外部狀態(tài)是可變部分,它應(yīng)當(dāng)客戶(hù)端來(lái)負(fù)責(zé)。


源碼在這里GitHub:
https://github.com/xiaonongOne/flyweight

注意啦! 往期設(shè)計(jì)模式在這里

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容