需求
撲克牌


問題,這里要創建 52 個 Card 對象,但這里花色只有四種是固定的,不同的是大小,可以用享元模式來共享對象,減少內存消耗。
什么是享元模式
“享” 是共享的意思,“元” 指的是元件,也就是小顆粒的東西,享元顧名思義便是共享小部件,很多系統或者程序包含大量對象,但是這些對象絕大多數都是差不多的,除了一些極個別的屬性外。當一個軟件系統在運行時產生的對象數量太多,將導致運行代價過高,帶來系統性能下降等問題。享元模式正為解決這一類問題而誕生。享元模式以共享的方式高效地支持大量細粒度對象的重用,在享元模式中,存儲這些共享實例對象的地方稱為享元池(Flyweight Pool)
代碼實現
抽象類

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 15:27
* @description
**/
public abstract class AbstractCard {
/**
* 得到顏色
*
* @return {@link String}
*/
public abstract String getColor();
/**
* 展示牌
*
* @param num 牌數
*/
public void showCards(String num) {
System.out.println("Card[牌色=" + getColor() + ",牌數=" + num + "]");
}
}
具體實現

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 15:42
* @description
**/
public class SpadeCard extends AbstractCard {
@Override
public String getColor() {
return "黑桃♠️";
}
}

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 15:49
* @description
**/
public class HeartCard extends AbstractCard {
@Override
public String getColor() {
return "紅桃♥";
}
}

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 15:50
* @description
**/
public class ClubsCard extends AbstractCard{
@Override
public String getColor() {
return "草花";
}
}

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 15:50
* @description
**/
public class DiamondsCard extends AbstractCard{
@Override
public String getColor() {
return "方塊";
}
}
工廠類

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 15:51
* @description
**/
public class CardFactory {
public static final int SPADE = 1;
public static final int CLUB = 2;
public static final int HEARTS = 3;
public static final int DIAMONDS = 4;
private static final Map<Integer, AbstractCard> CARD_MAP = new HashMap<>();
private static final CardFactory INSTANCE = new CardFactory();
private CardFactory() {
}
public static CardFactory getInstance() {
return INSTANCE;
}
public AbstractCard getCard(Integer color) {
if (CARD_MAP.containsKey(color)) {
System.out.println("復用對象");
return CARD_MAP.get(color);
} else {
System.out.println("新建對象");
AbstractCard card;
switch (color) {
case SPADE:
card = new SpadeCard();
break;
case CLUB:
card = new ClubsCard();
break;
case HEARTS:
card = new HeartCard();
break;
default:
card = new DiamondsCard();
break;
}
CARD_MAP.put(color, card);
return card;
}
}
}
客戶端使用

/**
* @author BNTang
* @program design-pattern-pro
* @date Created in 2021/10/09 009 16:00
* @description
**/
public class Client {
public static void main(String[] args) {
CardFactory cardFactory = CardFactory.getInstance();
IntStream.rangeClosed(0, 10).forEach(i -> {
AbstractCard card = null;
// 隨機花色
switch ((int) (Math.random() * 4)) {
case 0:
card = cardFactory.getCard(CardFactory.SPADE);
break;
case 1:
card = cardFactory.getCard(CardFactory.CLUB);
break;
case 2:
card = cardFactory.getCard(CardFactory.HEARTS);
break;
case 3:
card = cardFactory.getCard(CardFactory.DIAMONDS);
break;
}
// 隨機大小
if (null != card) {
int num = (int) (Math.random() * 13) + 1;
switch (num) {
case 11:
card.showCards("J");
break;
case 12:
card.showCards("Q");
break;
case 13:
card.showCards("K");
break;
default:
card.showCards(String.valueOf(num));
break;
}
}
});
}
}
運行結果如下:

角色
抽象享元角色(Flyweight)
是所有的具體享元類的基類,為具體享元規范需要實現的公共接口,非享元的外部狀態以參數的形式通過方法傳入。
具體享元(Concrete Flyweight)角色
實現抽象享元角色中所規定的接口。
非享元(Unsharable Flyweight)角色
是不可以共享的外部狀態,它以參數的形式注入具體享元的相關方法中。
享元工廠(Flyweight Factory)角色
負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶。如果不存在的話,則創建一個新的享元對象。
UML 圖


優缺點
優點,相同對象只要保存一份,這降低了系統中對象的數量,從而降低了系統中細粒度對象給內存帶來的壓力。缺點,為了使對象可以共享,需要將一些不能共享的狀態外部化,這將增加程序的復雜性。讀取享元模式的外部狀態會使得運行時間稍微變長。
源碼
- Interge.valueOf
- String
