設計模式--享元模式FlyWeight(結構型)

benbenxiongyuan發表於2014-04-15

1 定義:

1.1 定義:Use sharing to support large numbers of fine-grained objects efficiently.(使用共享物件可以有效地支援大量的細粒度的物件。)

細粒度物件:不可避免地使得物件數量多且性質相近,可將這些物件的資訊分為兩個部分:內部狀態(intrinsic)與外部狀態(extrinsic)。

內部狀態:物件可共享出來的資訊,儲存在享元物件的內部並且不會隨環境改變而改變

外部狀態:物件得以依賴的一個標記:隨環境改變而改變、不可以共享的狀態,享元物件的外蘊狀態必須由由端儲存,並在享元物件被建立之後,在需要使用的時候再傳入到享元物件內部

(理解舉例:享元模式在編輯器系統中大量使用。一個文編輯器往往會提供很多種字型,而通常的做法就是將每一個字母做成一個享元物件。享元物件的內蘊狀態就是這個字母,而字母在文字中的位置和字型風格等其他資訊則是外蘊狀態。比如,字母a可以出現在文字的很多地方,雖然這些字母a的位置和字型風格不同,但是所有這些地方使用的都是同一個字母物件。這樣一來,字母物件就可以在整個系統中共享。

1.2 通用類圖:

Flyweight——抽象享元角色

一個產品的抽象類,同時定義出物件的外部狀態和內部狀態的介面或實現。

ConcreteFlyweight——具體享元角色

實現抽象角色定義的業務。該角色中需要注意的是內部狀態處理應該與環境無關,不應該出現一個操作改變了內部狀態,同時修改了外部狀態,這是不允許的。

UnsharedConcreteFlyweight——不可共享的享元角色

不存在外部狀態或者安全要求(如執行緒安全)不能夠使用共享技術的物件,該物件一般不會出現在享元工廠中。

FlyweightFactory——享元工廠

職責非常簡單,就是構造一個池容器,同時提供從池中獲得物件的方式。

1.3 通用程式碼:

錯誤舉例:

 

package _22_Flyweight;
public abstract class Flyweight {
	private String intrinsic;
	protected String extrinsic;

	public Flyweight(String intrinsic) {
		this.intrinsic = intrinsic;
	}

	public String getIntrinsic() {
		return intrinsic;
	}

	public abstract void operate();

	public String getExtrinsic() {
		return extrinsic;
	}

	public void setExtrinisic(String extrinsic) {
		this.extrinsic = extrinsic;
	}
}

public class ConcreteFlyweight1 extends Flyweight {
	public ConcreteFlyweight1(String intrinsic) {
		super(intrinsic);
	}

	public void operate() {
	}
}

public class ConcreteFlyweight2 extends Flyweight {
	public ConcreteFlyweight2(String intrinsic) {
		super(intrinsic);
	}

	public void operate() {
	}
}

public class FlyweightFactory {
	private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();

	public static Flyweight getFlyweight1(String Intrinsic) {
		// 需要返回的物件
		Flyweight flyweight = pool.get(Intrinsic);
		if (flyweight == null) {
			flyweight = new ConcreteFlyweight1(Intrinsic);
			pool.put(Intrinsic, flyweight);
		}
		return flyweight;
	}

	public static int getSize() {
		return pool.size();
	}
}

public class Client {
	public static void main(String args[]) {
		Flyweight fly1 = FlyweightFactory.getFlyweight1("1234567890");
		fly1.setExtrinisic("Pos: line=10, col=20, color = RED");
		System.out.println(fly1.getExtrinsic() + " " + fly1.getIntrinsic());
		Flyweight fly2 = FlyweightFactory.getFlyweight1("1234567890");
		fly2.setExtrinisic("Pos: line=20, col=20, color = BLUE");
		System.out.println(fly2.getExtrinsic() + " " + fly2.getIntrinsic());
		System.out.println("池中數量為:" + FlyweightFactory.getSize());
	}
}

結果:

Pos: line=10, col=20, color = RED 1234567890

Pos: line=20, col=20, color = BLUE 1234567890

池中數量為:1

注意上述是一個誤用(錯例)。

享元模式只是想將物件細粒度化,將可共享部分快取起來,以複用。而上例中將物件的共享部分與非共享部分融合在一起是錯誤的,因為這樣則會導致整體的複用,在一個物件未被消費時,其會被另一次複用覆蓋。而這並非複用的本質。

下例正確:

 
package _22_Flyweight.right;
public abstract class Flyweight {
	private String intrinsic;

	public Flyweight(String intrinsic) {
		this.intrinsic = intrinsic;
	}

	public String getIntrinsic() {
		return intrinsic;
	}

	public abstract void operate();
}

public class ConcreteFlyweightContent extends Flyweight {
	public ConcreteFlyweightContent(String intrinsic) {
		super(intrinsic);
	}

	public void operate() {
	}
}

public class FlyweightFactory {
	private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();

	public static Flyweight getFlyweight1(String Intrinsic) {
		// 需要返回的物件
		Flyweight flyweight = pool.get(Intrinsic);
		if (flyweight == null) {
			flyweight = new ConcreteFlyweightContent(Intrinsic);
			pool.put(Intrinsic, flyweight);
		}
		return flyweight;
	}

	public static int getSize() {
		return pool.size();
	}
}

public class WPS {
	Flyweight fly;
	List<String> formats = new ArrayList<String>();
	List<Flyweight> contents = new ArrayList<Flyweight>();

	public void addLine(String format, Flyweight content) {
		formats.add(format);
		contents.add(content);
	}

	public void show() {
		for (int i = 0; i < formats.size(); i++) {
			System.out.print(formats.get(i) + "\t\t");
			System.out.println(contents.get(i).getIntrinsic());
		}
	}
}

public class Client {
	public static void main(String args[]) {
		WPS mydoc = new WPS();
		mydoc.addLine("Pos: line=1, col=20, color = RED",
				FlyweightFactory.getFlyweight1("1234567890"));
		mydoc.addLine("Pos: line=2, col=20, color = GREEN",
				FlyweightFactory.getFlyweight1("1234567890"));
		mydoc.addLine("Pos: line=3, col=20, color = BLUE",
				FlyweightFactory.getFlyweight1("1234567890"));
		mydoc.show();
		System.out.println("池中數量為:" + FlyweightFactory.getSize());
	}
}

2 優點

2.1 大大減少應用程式建立的物件,降低程式記憶體的佔用,增強程式的效能;

3 缺點

3.1 提高了系統的複雜性:需要分離出外部狀態和內部狀態;

4 應用場景

4.1 系統存在大量的相似物件;

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

4.3 需要緩衝池的場景。

5 注意事項

暫無

6 擴充套件

暫無

7 範例

暫無

轉自:http://blog.csdn.net/yuanlong_zheng/article/details/7584881

相關文章