享元模式


需求

撲克牌

image-20210926145508680

image-20210926145541303

問題,這里要創建 52Card 對象,但這里花色只有四種是固定的,不同的是大小,可以用享元模式來共享對象,減少內存消耗。

什么是享元模式

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

代碼實現

抽象類

image-20210926150120966

/**
 * @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 + "]");
    }
}

具體實現

image-20210926150231179

/**
 * @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 "黑桃♠️";
    }
}

image-20210926150247223

/**
 * @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 "紅桃♥";
    }
}

image-20210926150302314

/**
 * @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 "草花";
    }
}

image-20210926150320967

/**
 * @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 "方塊";
    }
}

工廠類

image-20210926150416722

/**
 * @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;
        }
    }
}

客戶端使用

image-20210926150453061

/**
 * @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;
                }
            }
        });
    }
}

運行結果如下:

image-20211010145521076

角色

抽象享元角色(Flyweight)

是所有的具體享元類的基類,為具體享元規范需要實現的公共接口,非享元的外部狀態以參數的形式通過方法傳入。

具體享元(Concrete Flyweight)角色

實現抽象享元角色中所規定的接口。

非享元(Unsharable Flyweight)角色

是不可以共享的外部狀態,它以參數的形式注入具體享元的相關方法中。

享元工廠(Flyweight Factory)角色

負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶。如果不存在的話,則創建一個新的享元對象。

UML 圖

image-20211010162108586

image-20211010162126101

優缺點

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

源碼

  • Interge.valueOf
  • String


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM