1.定義
用來盡可能減少內(nèi)存使用量,適用于可能存在大量重復(fù)對象的場景梅誓,來緩存可共享的對象桨螺。避免創(chuàng)建過多的對象宾符。
使用共享對象可有效地支持大量的細粒度的對象。
應(yīng)用場景:如果項目中有很多完全相同或相似的對象灭翔,則可以使用享元模式魏烫,節(jié)省內(nèi)存。
核心
享元對象能做到共享的關(guān)鍵就是區(qū)分了內(nèi)部狀態(tài)和外部狀態(tài)肝箱。
- 內(nèi)部狀態(tài):可以共享哄褒,不會隨環(huán)境變化而變化
- 外部狀態(tài):不可以共享,會隨環(huán)境變化而變化
例子:
火車購票系統(tǒng)煌张,很多客戶端不斷訪問服務(wù)器呐赡,服務(wù)器去查詢數(shù)據(jù)庫,然后返回給客戶端骏融;如果每次查詢結(jié)果都用創(chuàng)建的形式链嘀,
那么必將創(chuàng)建大量的對象;比如A-B城市档玻,就那么幾趟車怀泊,座位也就幾種;如果將這些數(shù)據(jù)緩存起來误趴,就不用每次都創(chuàng)建了霹琼。
當(dāng)數(shù)據(jù)庫查詢之后,先從緩存中取凉当,如果沒有在創(chuàng)建對象碧囊。
2.角色
FlyweightFactory(享元工廠類):創(chuàng)建并管理享元對象,享元池一般設(shè)計成鍵值對
FlyWeight(抽象享元類):通常是一個接口或者抽象類纤怒,聲明公共方法,這些方法可以向外界提供對象的內(nèi)部狀態(tài)天通,設(shè)置外部狀態(tài)泊窘。
ConcreteFlyWeight(具體享元類):為內(nèi)部狀態(tài)提供成員變量進行存儲
UnsharedConcreteFlyWeight(非共享享元類):不能被共享的子類可以設(shè)計為非共享享元類
3.代碼實現(xiàn)
例如:圍棋中的享元模式,在圍棋中,所有的白色或黑色的(形狀烘豹、大小瓜贾,顏色都一樣)只是位置不同,那像這樣的情況携悯,可以使用享元模式祭芦。
把顏色、形狀憔鬼、大小給共享出來(內(nèi)部狀態(tài))龟劲。位置不共享(外部狀態(tài))
FlyWeight(抽象享元類)
/**
* 享元類接口:可以共享的有顏色,大小轴或,形狀
* FlyWeight(抽象享元類):通常是一個接口或者抽象類昌跌,聲明公共方法,
* 這些方法可以向外界提供對象的內(nèi)部狀態(tài)照雁,設(shè)置外部狀態(tài)蚕愤。
*/
public interface ChessFlyWeight {
//這里只設(shè)置一個顏色,大小和形狀省略
void setColor(String c);
String getColor();
void display(Coordinate c);//顯示棋子
}
ConcreteFlyWeight(具體享元類):為內(nèi)部狀態(tài)提供成員變量進行存儲
//享元的具體實現(xiàn):ConcreteFlyWeight(具體享元類):為內(nèi)部狀態(tài)提供成員變量進行存儲
class concreteFlyWeight implements ChessFlyWeight{
private String color;//這里就是為內(nèi)部狀態(tài)提供成員變量進行存儲
//構(gòu)造的時候初始化color屬性
public concreteFlyWeight(String color) {
super();
this.color = color;
}
@Override
public void setColor(String c) {
this.color = c;
}
@Override
public String getColor() {
return color;
}
@Override
public void display(Coordinate c) {
System.out.println("棋子顏色:"+color);
System.out.println("棋子位置:("+c.getX()+","+c.getY()+")");
}
}
UnsharedConcreteFlyWeight(非共享享元類):不能被共享的子類可以設(shè)計為非共享享元類
/**
* 坐標(biāo)類(外部狀態(tài)):棋子位置
* UnsharedConcreteFlyWeight(非共享享元類):不能被共享的子類可以設(shè)計為非共享享元類
*/
public class Coordinate {
private int x,y;//坐標(biāo)位置
public Coordinate(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
FlyweightFactory(享元工廠類)
/**
* 享元工廠
* FlyweightFactory(享元工廠類):創(chuàng)建并管理享元對象,享元池一般設(shè)計成鍵值對
*/
public class ChessFlyWeightFactory {
//享元池:存放享元對象
private static Map<String,ChessFlyWeight> map = new HashMap<String,ChessFlyWeight>();
//提供一個享元工廠:創(chuàng)建和管理棋子
public static ChessFlyWeight getChess(String color){
if (map.get(color) != null ) {
return map.get(color);
}else{
ChessFlyWeight chess = new concreteFlyWeight(color);
map.put(color, chess);
return chess;
}
}
}
客戶端
public static void main(String[] args) {
ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色");//黑1
ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色");//黑2
System.out.println(chess1==chess2);//結(jié)果為true饺蚊,相同或相似對象內(nèi)存中只存在一份
//使用享元的外部狀態(tài)
chess1.display(new Coordinate(10, 10));//黑1在10,10的位置
chess2.display(new Coordinate(20, 20));//黑2在20,20的位置
}
輸出結(jié)果
true
棋子顏色:黑色
棋子位置:(10,10)
棋子顏色:黑色
棋子位置:(20,20)
4.總結(jié)
應(yīng)用場景
比如線程池萍诱,數(shù)據(jù)庫連接池,這些都利用享元模式共享了部分屬性污呼,在池中操作裕坊。
String類的設(shè)計也是享元模式
優(yōu)點:
1.極大的減少內(nèi)存中對象的數(shù)量
2.相同或相似對象內(nèi)存中只存在一份,極大的節(jié)約資源曙求,提高系統(tǒng)性能
3.外部狀態(tài)相對獨立碍庵,不影響內(nèi)部狀態(tài)
缺點:
1.模式較復(fù)雜,使程序邏輯復(fù)雜化
2.為了節(jié)省內(nèi)存悟狱,共享了內(nèi)部狀態(tài)静浴,分離出外部狀態(tài),而讀取外部狀態(tài)使運行時間變長挤渐。
5.Android中
android handler的消息隊列中消息的不斷創(chuàng)建苹享、更新、銷毀浴麻,可以利用享元模式得问;