一咖祭、基礎(chǔ)簡介
1、定義
運(yùn)用共享技術(shù)有效地支持大量細(xì)顆粒度的對象蔫骂。主要用于減少創(chuàng)建對象的數(shù)量么翰,以減少內(nèi)存占用和提高性能。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式纠吴。
2硬鞍、使用場景
- 1、系統(tǒng)中有大量對象戴已。
- 2固该、這些對象消耗大量內(nèi)存。
- 3糖儡、這些對象的狀態(tài)大部分可以外部化伐坏。
- 4、這些對象可以按照內(nèi)蘊(yùn)狀態(tài)分為很多組握联,當(dāng)把外蘊(yùn)對象從對象中剔除出來時(shí)桦沉,每一組對象都可以用一個(gè)對象來代替每瞒。
- 5、系統(tǒng)不依賴于這些對象身份纯露,這些對象是不可分辨的剿骨。
3、優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 可以極大減少內(nèi)存中對象的數(shù)量埠褪,使得相同或相似對象在內(nèi)存中只保存一份浓利,從而可以節(jié)約系統(tǒng)資源,提高系統(tǒng)性能钞速。
- 享元模式的外部狀態(tài)相對獨(dú)立贷掖,而且不會(huì)影響其內(nèi)部狀態(tài),從而使得享元對象可以在不同的環(huán)境中被共享
缺點(diǎn):提高了系統(tǒng)的復(fù)雜度渴语,需要分離出外部狀態(tài)和內(nèi)部狀態(tài)苹威,而且外部狀態(tài)具有固有化的性質(zhì),不應(yīng)該隨著內(nèi)部狀態(tài)的變化而變化驾凶,否則會(huì)造成系統(tǒng)的混亂牙甫。
4、模式結(jié)構(gòu)分析
- Flyweight(抽象享元類):通常是一個(gè)接口或抽象類狭郑,在抽象享元類中聲明了具體享元類公共的方法腹暖,這些方法可以向外界提供享元對象的內(nèi)部數(shù)據(jù)(內(nèi)部狀態(tài)),同時(shí)也可以通過這些方法來設(shè)置外部數(shù)據(jù)(外部狀態(tài))翰萨。
- ConcreteFlyweight(具體享元類):它實(shí)現(xiàn)了抽象享元類,其實(shí)例稱為享元對象糕殉;在具體享元類中為內(nèi)部狀態(tài)提供了存儲空間亩鬼。通常我們可以結(jié)合單例模式來設(shè)計(jì)具體享元類,為每一個(gè)具體享元類提供唯一的享元對象阿蝶。
- UnsharedConcreteFlyweight(非共享具體享元類):并不是所有的抽象享元類的子類都需要被共享雳锋,不能被共享的子類可設(shè)計(jì)為非共享具體享元類;當(dāng)需要一個(gè)非共享具體享元類的對象時(shí)可以直接通過實(shí)例化創(chuàng)建羡洁。
- FlyweightFactory(享元工廠類):享元工廠類用于創(chuàng)建并管理享元對象玷过,它針對抽象享元類編程,將各種類型的具體享元對象存儲在一個(gè)享元池中筑煮,享元池一般設(shè)計(jì)為一個(gè)存儲“鍵值對”的集合(也可以是其他類型的集合)辛蚊,可以結(jié)合工廠模式進(jìn)行設(shè)計(jì);當(dāng)用戶請求一個(gè)具體享元對象時(shí)真仲,享元工廠提供一個(gè)存儲在享元池中已創(chuàng)建的實(shí)例或者創(chuàng)建一個(gè)新的實(shí)例(如果不存在的話)袋马,返回新創(chuàng)建的實(shí)例并將其存儲在享元池中。
二秸应、實(shí)例實(shí)現(xiàn)
1虑凛、實(shí)例場景
比如“五子棋”碑宴,有白色和黑色的棋子:
- 棋子:就是一個(gè) Flyweight(抽象享元類)
- 棋子的顏色:就屬于“內(nèi)部狀態(tài)”
- 棋子的位置:就屬于“外部狀態(tài)”
- 白棋和黑棋,就是ConcreteFlyweight(具體享元類)
- 而壞了的棋子桑谍,就是UnsharedConcreteFlyweight(非共享具體享元類)
- 五子棋加工廠延柠,就是 FlyweightFactory(享元工廠類)
2、“五子棋”:Flyweight(抽象享元類)
package com.mfc.design.享元模式.實(shí)例;
/**
* @author MouFangCai
* @date 2019/10/25 14:29
*
* @description 五子棋棋子類:Flyweight(抽象享元類)
*/
public abstract class Chessman_Flyweight {
public abstract void display();
// 通過該接口锣披,F(xiàn)lyweight可以接受并作用于外部狀態(tài)
public abstract void display(Coord_Extrinsic extrinsic);
}
3贞间、外部狀態(tài)類
package com.mfc.design.享元模式.實(shí)例;
import lombok.Data;
/**
* @author MouFangCai
* @date 2019/10/25 14:33
* @description 棋子的外部屬性:坐標(biāo)類
*/
@Data
public class Coord_Extrinsic {
private int x;
private int y;
public Coord_Extrinsic(int x, int y) {
this.x = x;
this.y = y;
}
}
4、白棋 / 黑棋:ConcreteFlyweight(具體享元類)
package com.mfc.design.享元模式.實(shí)例;
/**
* @author MouFangCai
* @date 2019/10/25 14:48
*
* @description 具體的棋子:ConcreteFlyweight(具體享元類):它實(shí)現(xiàn)了抽象享元類盈罐,其實(shí)例稱為享元對象
*/
public class Chessman_ConcreteFlyweight extends Chessman_Flyweight{
// 為內(nèi)部狀態(tài)增加存儲空間
// 棋子的內(nèi)部屬性:顏色
private String color_intrinsic;
// 要求享元角色 必須接受內(nèi)部狀態(tài)
public Chessman_ConcreteFlyweight(String color_intrinsic) {
this.color_intrinsic = color_intrinsic;
}
@Override
public void display() {
System.out.println("棋子顏色:" + color_intrinsic + " 在棋盒里");
}
@Override
public void display(Coord_Extrinsic extrinsic) {
System.out.println("棋子顏色:" + color_intrinsic +
" 位置:(" + extrinsic.getX() + "," + extrinsic.getY() + ")");
}
}
5榜跌、壞了的棋子:UnsharedConcreteFlyweight(非共享具體享元類)
package com.mfc.design.享元模式.實(shí)例;
/**
* @author MouFangCai
* @date 2019/10/25 14:58
* @description UnsharedConcreteFlyweight(非共享具體享元類)
* 壞了的棋子就不管他的顏色了
*/
public class UnsharedConcreteFlyweight extends Chessman_Flyweight {
@Override
public void display() {
System.out.println("這個(gè)棋子已壞");
}
@Override
public void display(Coord_Extrinsic extrinsic) {
System.out.println("這個(gè)棋子已壞");
}
}
6、五子棋加工廠: FlyweightFactory(享元工廠類)
package com.mfc.design.享元模式.實(shí)例;
import java.util.HashMap;
/**
* @author MouFangCai
* @date 2019/10/25 15:01
* @description FlyweightFactory(享元工廠類):享元工廠類用于創(chuàng)建并管理享元對象
*/
public class Chessman_Factory {
// 使用HashMap存儲享元對象盅粪,充當(dāng)享元池
private static HashMap<String,Chessman_Flyweight> chessmanMaps;
// 使用單例模式钓葫,保證Chessman_Factory 類只有一個(gè)實(shí)例
private static class FactoryClass {
private static final Chessman_Factory chessman = new Chessman_Factory();
}
// 初始化常用的棋子
private Chessman_Factory() {
chessmanMaps = new HashMap<>();
Chessman_Flyweight white = new Chessman_ConcreteFlyweight("白色");
chessmanMaps.put("w",white);
Chessman_Flyweight black = new Chessman_ConcreteFlyweight("黑色");
chessmanMaps.put("b",black);
Chessman_Flyweight unshared = new UnsharedConcreteFlyweight();
chessmanMaps.put("no",unshared);
}
// 得到 享元工廠類的唯一實(shí)例
public static Chessman_Factory getFactory() {
return FactoryClass.chessman;
}
public Chessman_Flyweight getFlyweight(String color){
return chessmanMaps.get(color);
}
// 實(shí)例數(shù)
public int getCount(){
return chessmanMaps.size();
}
}
7、客戶端
package com.mfc.design.享元模式.實(shí)例;
/**
* @author MouFangCai
* @date 2019/10/25 15:01
* @description
*/
public class Client_Flyweight {
public static void main(String[] args) {
// 獲取享元工廠對象
Chessman_Factory factory = Chessman_Factory.getFactory();
// 獲取2枚黑棋票顾、2枚白棋础浮、2枚壞了的棋子
Chessman_Flyweight black1 = factory.getFlyweight("b");
Chessman_Flyweight black2 = factory.getFlyweight("b");
System.out.println("判斷黑棋是否相同:" + (black1 == black2));
Chessman_Flyweight white1 = factory.getFlyweight("w");
Chessman_Flyweight white2 = factory.getFlyweight("w");
System.out.println("判斷白棋是否相同:" + (white1 == white2));
Chessman_Flyweight bad1 = factory.getFlyweight("no");
Chessman_Flyweight bad2 = factory.getFlyweight("no");
System.out.println("判斷壞了的棋子是否相同:" + (bad1 == bad2));
System.out.println();
System.out.println("棋子的實(shí)例數(shù):" + factory.getCount());
System.out.println();
// 顯示棋子
black1.display();
white1.display();
bad1.display();
// 顯示棋子,同時(shí)設(shè)置坐標(biāo)位置
System.out.println();
black2.display(new Coord_Extrinsic(1,2));
white2.display(new Coord_Extrinsic(2,3));
bad2.display(new Coord_Extrinsic(1,2));
}
}
8、結(jié)果展示
判斷黑棋是否相同:true
判斷白棋是否相同:true
判斷壞了的棋子是否相同:true棋子的實(shí)例數(shù):3
棋子顏色:黑色 在棋盒里
棋子顏色:白色 在棋盒里
這個(gè)棋子已壞棋子顏色:黑色 位置:(1,2)
棋子顏色:白色 位置:(2,3)
這個(gè)棋子已壞Process finished with exit code 0
我們可以看到奠骄,棋子的實(shí)例數(shù)為3豆同,但我們已有6顆棋子了。減少了創(chuàng)建對象的數(shù)量