设计模式之享元模式(Flyweight Design Pattern)

享元模式是八种结构型模式之一,享元就是共享单元(元素)的意思。单元代表了整体的部分,如果一个对象其中的部分是稳定的不会改变的,那么这个部分即可以共享。享元模式的用途就是复用对象的单元,让对象的节省内存。

后面用扑克牌举例如何使用享元模式。

斗地主相信很多人都玩过,一副版,黑红花方四色,每一色都有从2到A的13张牌,加上大小王,共有54张牌。假如一张牌就是一个对象,一张桌子就要54个对象;一个牌室300张桌子;一个服务器有50个牌室;这样的服务器可能又有200个。那这样的对象就是54*300*50*200=162000000个。


/**
 * 花色
 */
public enum Color {
    /**
     * 红心
     */
    heart,
    /**
     * 黑桃
     */
    spade,
    /**
     * 梅花
     */
    club,
    /**
     * 方块
     */
    diamond,
    /**
     * 大小王
     */
    joker

}

/**
 * 一张牌
 */
public class Card {
    /**
     * 编号,用于牌比较大小,1-13,小王14,大王15
     */
    private int num;
    /**
     * 名称
     */
    private String name;
    /**
     * 花色
     */
    private Color color;
    /**
     * 出牌状态
     */
    Card(int num, String name, Color color){
        this.num = num; this.name = name; this.color = color;
    }

    /**
     * 出牌
     */
    public void play(){
        this.status =  true;
    }

    /**
     * 洗牌
     */
    public void shuffle(){
        this.status =  false;
    }

    @Override
    public String toString() {
        return "Card{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", color=" + color +
                '}';
    }
}

/**
 * 一副牌
 */
public class Deck {
    List<Card> cardList;
    Deck(){
        cardList = new ArrayList<>(54);
        cardList.add(new Card(1,"2",Color.spade));//黑桃2
        ...省略中间的牌
        cardList.add(new Card(13,"A",Color.spade));//黑桃A
        cardList.add(new Card(1,"2",Color.heart));//红星2
        ...省略中间的牌
        cardList.add(new Card(13,"A",Color.heart));//红星A
        cardList.add(new Card(1,"2",Color.club));//梅花2
        ...省略中间的牌
        cardList.add(new Card(13,"A",Color.club));//梅花A
        cardList.add(new Card(1,"2",Color.diamond));//方块2
        ...省略中间的牌
        cardList.add(new Card(13,"A",Color.diamond));//方块A
        cardList.add(new Card(14,"小王",Color.joker));//小王
        cardList.add(new Card(15,"大王",Color.joker));//大王
    }

    /**
     * 洗牌
     */
    public void shuffle(){
        Card[] objects = this.cardList.stream().toArray(Card[]::new);
        int size = this.cardList.size();
        //把牌顺序打乱
        for(int i = 0; i < size; i++){
            int currentRandom = (int)(Math.random() * (size - 1));
            Card current = objects[i];
            objects[i] = objects[currentRandom];
            objects[currentRandom] = current;
        }
        this.cardList.clear();
        this.cardList= Arrays.asList(objects);
        //设置牌状态为未出牌
        this.cardList.forEach(card -> {
            card.shuffle();
            System.out.println(card.toString());
        });
    }

}

打过牌的人都知道每一幅牌里的牌都是一样的。不管哪幅牌,牌的数量和同样一张牌的编号、名称、花色都是一样的且不会变化,所以可以提取这些单元做为共享单元,让所有牌共享。

/**
 * 一张牌的共享单元
 */
public class CardUnit {
    /**
     * 编号,用于牌比较大小,1-13,小王14,大王15
     */
    private int num;
    /**
     * 名称
     */
    private String name;
    /**
     * 花色
     */
    private Color color;

    CardUnit(int num, String name, Color color){
        this.num = num; this.name = name; this.color = color;
    }

    @Override
    public String toString() {
        return "CardUnit{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", color=" + color +
                '}';
    }
}

/**
 * 共享单元的工厂类
 */
public class CardUnitFactory {
    private static final Map<Integer,CardUnit> cardUnitMap = new HashMap<>(54);
    static {
        cardUnitMap.put(1, new CardUnit(1,"2",Color.spade));//黑桃2
        //....
        cardUnitMap.put(13, new CardUnit(13,"A",Color.spade));//黑桃A
        cardUnitMap.put(14, new CardUnit(1,"2",Color.heart));//红星2
        //....
        cardUnitMap.put(26, new CardUnit(13,"A",Color.heart));//红星A
        cardUnitMap.put(27, new CardUnit(1,"2",Color.club));//梅花2
        //....
        cardUnitMap.put(39, new CardUnit(13,"A",Color.club));//梅花A
        cardUnitMap.put(40, new CardUnit(1,"2",Color.diamond));//方块2
        //....
        cardUnitMap.put(52, new CardUnit(13,"A",Color.diamond));//方块A
        cardUnitMap.put(53, new CardUnit(14,"小王",Color.joker));//小王
        cardUnitMap.put(54, new CardUnit(15,"大王",Color.joker));//大王
    }
    public static CardUnit getCardUnit(Integer id) { return cardUnitMap.get(id); }
}

/**
 * 一张牌
 */
public class Card {
    private CardUnit cardUnit;
    /**
     * 出牌状态
     */
    private boolean status;
    Card(CardUnit cardUnit){
        this.cardUnit = cardUnit;
    }

    /**
     * 出牌
     */
    public void play(){
        this.status =  true;
    }

    /**
     * 洗牌
     */
    public void shuffle(){
        this.status =  false;
    }

    @Override
    public String toString() {
        return "Card{" +
                "cardUnit=" + cardUnit +
                ", status=" + status +
                '}';
    }
}

/**
 * 一副牌
 */
public class Deck {

    List<Card> cardList;

    Deck(){
        cardList = new ArrayList<>(54);
        cardList.add(new Card(CardUnitFactory.getCardUnit(1)));//黑桃2
        //...省略中间的牌
        cardList.add(new Card(CardUnitFactory.getCardUnit(13)));//黑桃A
        cardList.add(new Card(CardUnitFactory.getCardUnit(14)));//红星2
        //...省略中间的牌
        cardList.add(new Card(CardUnitFactory.getCardUnit(26)));//红星A
        cardList.add(new Card(CardUnitFactory.getCardUnit(27)));//梅花2
        //...省略中间的牌
        cardList.add(new Card(CardUnitFactory.getCardUnit(39)));//梅花A
        cardList.add(new Card(CardUnitFactory.getCardUnit(40)));//方块2
        //...省略中间的牌
        cardList.add(new Card(CardUnitFactory.getCardUnit(52)));//方块A
        cardList.add(new Card(CardUnitFactory.getCardUnit(53)));//小王
        cardList.add(new Card(CardUnitFactory.getCardUnit(54)));//大王
    }

    /**
     * 洗牌
     */
    public void shuffle(){

        Card[] objects = this.cardList.stream().toArray(Card[]::new);
        int size = this.cardList.size();

        //把牌顺序打乱
        for(int i = 0; i < size; i++){
            int currentRandom = (int)(Math.random() * (size - 1));
            Card current = objects[i];
            objects[i] = objects[currentRandom];
            objects[currentRandom] = current;
        }

        this.cardList.clear();
        this.cardList= Arrays.asList(objects);

        //设置牌状态为未出牌
        this.cardList.forEach(card -> {
            card.shuffle();
            System.out.println(card.toString());
        });
    }
}

总结

共享模式就是把对象中稳定不变化的单元,提取出来做为共享单元,并使用工厂类来创建共享单元。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值