**定義**:使用共享對象可有效的支持大量的細粒度的對象。
享元模式的定義為我們提出了兩個要求:細粒度的對象和共享對象。
我們知道分配太多的對象到應用程序中將有損程序的性能,同時還容易造成內存溢出。享元模式就可以有效的避免。
細粒度對象由于是對象數量多且性質相近,我們將這些對象分為兩個部分:內部狀態和外部狀態。
內部狀態:
---|內部狀態是對象可共享出來的信息,存儲在享元對象內部并且不會隨環境改變而改變。如id,address等。
外部狀態:
---|外部狀態是對象得以依賴的一個標記,是隨環境改變而改變的、不可以共享的狀態。如考試科目+考試地點等。
## 一般模式

Flyweight抽象享元角色
---|產品的抽象類,定義出對象的外部狀態和內部狀態的接口或實現
ConcreteFlyweight具體享元角色
---|實現抽象角色定義的義務。該角色要注意內部狀態處理與環境無關,不能出現一個操作改變內部狀態,同時修改外部狀態。
unShareConcreteFlyweight不可共享的享元角色
---|不存在外部狀態或者安全要求不能夠使用共享技術的對象,該對象一般不會出現在享元工廠中。
FlyweightFactory享元工廠
---|職責非常簡單,就是構造一個池容器,同時提供從池中獲得對象的方法。
~~~
public class FlyweightTest {
}
/**
* 抽象的享元角色。
* 定義出對象的外部狀態和內部狀態的接口和實現。
* @author admin
*/
abstract class Flyweight{
//內部狀態
private String intrinsic;
//外部狀態
protected String extrinsic;
//構造方法提供外部字符串
public Flyweight(String extrinsic) {
this.extrinsic = extrinsic;
}
//定義業務操作
public abstract void operate();
//內部狀態的getter和
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
/**
* 具體的享元角色
* @author admin
*/
class ConcreteFlyweight1 extends Flyweight{
public ConcreteFlyweight1(String extrinsic) {
super(extrinsic);
}
@Override
public void operate() {
System.out.println("享元角色1...操作");
}
}
/**
* 具體的享元角色
* @author admin
*/
class ConcreteFlyweight2 extends Flyweight{
public ConcreteFlyweight2(String extrinsic) {
super(extrinsic);
}
@Override
public void operate() {
System.out.println("享元角色2...操作");
}
}
/**
* 享元工廠角色
* @author admin
*/
class FlyweightFactory{
//定義一個容器
private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
//享元工廠
public static Flyweight getFlyweight(String extrinsic){
//需要返回的對象
Flyweight flyweight=null;
if(!pool.containsKey(extrinsic)){
//根據外部狀態創建享元對象
flyweight = new ConcreteFlyweight1(extrinsic);
pool.put(extrinsic, flyweight);
}else{
flyweight = pool.get(extrinsic);
}
return flyweight;
}
}
~~~
## 一個例子
一個學生報考系統,該系統限時3天注冊并報名。每天的訪問量達上百萬,人數極多。系統開發完,出現了OOM內存溢出
的狀況。產生該問題的原因有兩種:
1、內存溢出(無意識的代碼缺陷,導致JVM不能獲得連續的內存空間)
2、對象太多,把內存耗盡了。
享元模式來解決,來限制對象的創建。

~~~
public class FlyweightT {
public static void main(String[] args) {
//創建對象
for(int i=0;i<4;i++){
String subject = "科目"+i;
for(int j=0;j<30;j++){
String location = "地點"+j;
SignInfo signInfo = SignInfoFactory.getSignInfo(subject+location);
}
}
SignInfo s = SignInfoFactory.getSignInfo("科目3地點4");
}
}
/**
* 抽象的學生享元角色
* 提供學生的一些基本信息。
* @author admin
*/
abstract class SignInfo{
//學生id
private String id;
//學生考試地點
private String location;
//考試科目
private String subject;
//考試
private String postAddress;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getPostAddress() {
return postAddress;
}
public void setPostAddress(String postAddress) {
this.postAddress = postAddress;
}
}
/**
* 具體的享元角色,
* 設置外部狀態。
* @author admin
*
*/
class SignInfo4Pool extends SignInfo{
private String key;
public SignInfo4Pool(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
/**
* 享元工廠類。
* 創建對象享元對象
* @author admin
*
*/
class SignInfoFactory{
private static HashMap<String, SignInfo> pool = new HashMap<String, SignInfo>();
public static SignInfo getSignInfo(String key){
SignInfo signInfo =null;
if(pool.containsKey(key)){
System.out.println("從對象池中獲取...");
signInfo = pool.get(key);
}else{
System.out.println("創建新對象...");
signInfo = new SignInfo4Pool(key);
pool.put(key, signInfo);
}
return signInfo;
}
}
~~~
**享元模式的優缺點:**
大大減少了應用程序創建的對象,降低程序內存的占用,增強程序的性能。
使用享元模式時,外部狀態盡量使用java提供的基本數據類型,提高程序的性能。
**使用場景:**
系統中存在大量的相似對象,細粒度的對象都具備較接近的外部狀態,而且內部狀態與環境無關,也就是對象沒有特定身份,需要緩沖池的場景
- 前言
- 6大設計原則(一)---單一職責原則
- 6大設計原則(二)---里氏替換原則
- 6大設計原則(三)---依賴倒置原則
- 6大設計模式(四)----接口隔離原則
- 6大設計原則(五)---迪米特法則
- 6大設計原則(六)---開閉原則。
- 設計模式(一)---單例模式
- 設計模式(二)---工廠方法模式
- 設計模式(三)---抽象工廠模式
- 設計模式(四)---模板方法模式
- 設計模式(五)---建造者模式
- 設計模式(六)---代理模式
- 設計模式(七)---原型模式
- 設計模式(八)---中介者模式
- 設計模式(九)---命令模式
- 設計模式(十)---責任鏈模式
- 設計模式(十一)---裝飾模式
- 設計模式(十二)---策略模式
- 設計模式(十三)---適配器模式
- 設計模式(十四)---迭代器模式
- 設計模式(十五)---組合模式
- 設計模式(十六)---觀察者模式
- 設計模式(十七)---門面模式
- 設計模式(十八)---備忘錄模式
- 設計模式(十八)---訪問者模式
- 設計模式(二十)---狀態模式
- 設計模式(二十二)---享元模式
- 設計模式(二十三)---橋梁模式