一、概述
享元模式:“享”就是分享之意,指一物被衆人共享,而這也正是該模式的終旨所在。
享元模式有點類似於單例模式,都是隻生成一個對象來被共享使用。這裏有個問題,那就是對共享對象的修改,爲了避免出現這種情況,我們將這些對象的公共部分,或者說是不變化的部分抽取出來形成一個對象。這個對象就可以避免到修改的問題。
享元的目的是爲了減少不會要額內存消耗,將多個對同一對象的訪問集中起來,不必爲每個訪問者創建一個單獨的對象,以此來降低內存的消耗。
二、示例
下面我們來看一個簡單的例子:
建築接口:JianZhu
public interface Jianzhu {
void use();
}
體育館實現類:TiYuGuan
public class TiYuGuan implements Jianzhu {
private String name;
private String shape;
private String yundong;
public TiYuGuan(String yundong){
this.setYundong(yundong);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getYundong() {
return yundong;
}
public void setYundong(String yundong) {
this.yundong = yundong;
}
@Override
public void use() {
System.out.println("該體育館被使用來召開奧運會" + " 運動爲:"+ yundong+" 形狀爲:"+shape+ " 名稱爲:"+name);
}
}
建築工廠類:JianZhuFactory
import java.util.*;
public class JianZhuFactory {
private static final Map<String,TiYuGuan> tygs = new HashMap<String,TiYuGuan>();
public static TiYuGuan getTyg(String yundong){
TiYuGuan tyg = tygs.get(yundong);
if(tyg == null){
tyg = new TiYuGuan(yundong);
tygs.put(yundong,tyg);
}
return tyg;
}
public static int getSize(){
return tygs.size();
}
}
測試類:Clienter
public class Clienter {
public static void main(String[] args) {
String yundong ="足球";
for(int i = 1;i <= 5;i++){
TiYuGuan tyg = JianZhuFactory.getTyg(yundong);
tyg.setName("中國體育館");
tyg.setShape("圓形");
tyg.use();
System.out.println("對象池中對象數量爲:"+JianZhuFactory.getSize());
}
}
}
執行結果:
該體育館被使用來召開奧運會 運動爲:足球 形狀爲:圓形 名稱爲:中國體育館
對象池中對象數量爲:1
該體育館被使用來召開奧運會 運動爲:足球 形狀爲:圓形 名稱爲:中國體育館
對象池中對象數量爲:1
該體育館被使用來召開奧運會 運動爲:足球 形狀爲:圓形 名稱爲:中國體育館
對象池中對象數量爲:1
該體育館被使用來召開奧運會 運動爲:足球 形狀爲:圓形 名稱爲:中國體育館
對象池中對象數量爲:1
該體育館被使用來召開奧運會 運動爲:足球 形狀爲:圓形 名稱爲:中國體育館
對象池中對象數量爲:1
三、模式解析
如上示例中,使用工廠模式進行配合,創建對象池,測試類中的循環,你可以想象成爲要舉行5場比賽,每場比賽的場地就是體育館
通過執行結果可以看出,在這個對象池(HashMap)中,一直都只有一個對象存在,第一次使用的時候創建對象,之後的每次調用都用的是那個對象,不會再重新創建。
其實在Java中就存在這種類型的實例:String。
Java中將String類定義爲final(不可改變的),JVM中字符串一般保存在字符串常量池中,這個字符串常量池在jdk 6.0以前是位於常量池中,位於永久代,而在JDK 7.0中,JVM將其從永久代拿出來放置於堆中。
我們使用如下代碼定義的兩個字符串指向的其實是同一個字符串常量池中的字符串值。
String s1 = "abc";
String s2 = "abc";
如果我們以s1==s2進行比較的話所得結果爲:true,因爲s1和s2保存的是字符串常量池中的同一個字符串地址。這就類似於我們今天所講述的享元模式,字符串一旦定義之後就可以被共享使用,因爲他們是不可改變的,同時被多處調用也不會存在任何隱患。
四、使用場景
當我們項目中創建很多對象,而且這些對象存在許多相同模塊,這時,我們可以將這些相同的模塊提取出來採用享元模式生成單一對象,再使用這個對象與之前的諸多對象進行配合使用,這樣無疑會節省很多空間。