??以前想騎自行車(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