1. 程式人生 > >Java設計模式----享元模式(FlyWeight)

Java設計模式----享元模式(FlyWeight)

1.  享元模式定義:

     享元模式是池技術的重要實現原理,定義如下:使用共享物件可以有效的支援大量的細粒度物件

    內部狀態:儲存在享元物件內部不隨外部環境改變可以共享出來的資訊

    外部狀態:外部狀態是物件得以依賴的一個標記,是隨外部環境改變而變化、不可以共享的狀態

2.  享元模式的角色名稱:

      a.  抽象享元角色

      簡單地說,就是一個產品的抽象類,它同時定義了物件的內部狀態和外部狀態,以及介面和實現

     b. 具體的享元物件

     具體的產品類,實現了抽象產品類定義的業務

    c.  享元工廠

    提供一個池容器,同時提供從池中獲取物件的方法

3.  享元模式通用示例程式碼:

抽象享元角色類:

public abstract class FlyWeight {
    
	//內部狀態
	private String intrinsic; 
	private String name;
	//外部狀態
	protected final String extrinsic;
	
	//要求享元角色必須接受外部狀態
	public FlyWeight(String extrinsic) {
		this.extrinsic=extrinsic;
	}
	
	//定義業務操作
	public abstract void  operator();
    
	//內部狀態的getter/setter
	public String getIntrinsic() {
		return intrinsic;
	}

	public void setIntrinsic(String intrinsic) {
		this.intrinsic = intrinsic;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
		
}
抽象享元角色類一般是一個抽象類,一般要把外部狀態和內部狀態定義出來,避免子類隨意的擴充套件。

具體的享元角色類:

public class FlyWeight1 extends FlyWeight{
   
	public FlyWeight1(String extrinsic) {
		super(extrinsic);
	}

	@Override
	public void operator() {
		
		System.out.println("業務操作方法...內部狀態是:"+super.getIntrinsic());
		
	}
}
享元工廠類:
public class FlyWeightFactory {
   
	private static HashMap<String,FlyWeight> pool=new HashMap<String,FlyWeight>();
	
	public static  FlyWeight getInstance(String key){
		//需要返回的物件
		FlyWeight flyWeight=null;
		//如果池中存在該物件,直接獲取返回
		if(pool.containsKey(key)){
			System.out.println(key+"-----池中存在,直接從物件池中取得");
			flyWeight=pool.get(key);
		}else{
			//池中不存在此物件,根據外部狀態新建一個物件返回
			System.out.println(key+"-----池中不存在,建立物件並放到物件池中");
			flyWeight=new FlyWeight1(key);
			//放置到池中
			pool.put(key, flyWeight);
		}
		return flyWeight;
	}
	
	/**
	 * 初始化物件池
	 * @param size
	 */
	public static void initObjectPool(int size){
		for (int i = 0; i <= size; i++) {
			FlyWeightFactory.getInstance("物件"+i);
		}
	}
}
測試類:
public class Test {
   
	public static void main(String[] args) {
		//初始化物件池
		FlyWeightFactory.initObjectPool(4);
		FlyWeight flyWeight=FlyWeightFactory.getInstance("物件1");
		flyWeight.setIntrinsic("這是單獨設定的內部狀態!");
		flyWeight.operator();
	}
}
結果:
物件0-----池中不存在,建立物件並放到物件池中
物件1-----池中不存在,建立物件並放到物件池中
物件2-----池中不存在,建立物件並放到物件池中
物件3-----池中不存在,建立物件並放到物件池中
物件4-----池中不存在,建立物件並放到物件池中
物件1-----池中存在,直接從物件池中取得
業務操作方法...內部狀態是:這是單獨設定的內部狀態!
4.   享元模式的優點和缺點

      享元模式是可以大大減少應用程式建立物件的時間,降低程式記憶體的佔用,增強程式的效能,同時它也大大加大了程式的複雜度,因為需要分離外部狀態和內部狀態。

5.  享元模式的使用場景

          在如下場景中則可以選擇使用享元模式。

● 系統中存在大量的相似物件。

● 細粒度的物件都具備較接近的外部狀態,而且內部狀態與環境無關,也就是說物件沒有特定身份。

● 需要緩衝池的場景。

6.  享元模式的執行緒安全問題:

     由於使用的是共享物件,所以很可能會出現2個執行緒共用一個物件並且同時修改的問題,這樣就會出現執行緒安全問題。為了儘可能避免這個問題,要儘量的加大物件池中物件的數量,並且對於外部狀態,最好可以使用多個字串的組合來確定key值(即物件池中,一個物件對應一個key值)