0x0、引言
🤡提测了等改BUG,摸鱼时啃下《设计模式之美》,本文对应设计模式与范式:结构型(54-55),享元模式
(Flyweight Pattern),结构型设计模式最后一个~
- 很好理解 →
享元,被共享的单元
- 意图 →
节省内存,复用不可变对象
- 换句话说 →
找出相似对象间的共有特征,然后复用这些特征
。
一个形象的例子:游戏开发中,一个森林场景,成千上万种树,每棵树都实例化不同的模型,内存直接爆炸,可以抽取出所有树对象的共有属性,转移到一个单独的类中,然后只需要一个类实例,然后森林里的每一颗树对这个实例做一次引用(图摘自:Flyweight):
网络异常,图片无法展示
|
Tips:二手知识加工难免有所纰漏,感兴趣有时间的可自行查阅原文,谢谢。
0x1、写个简单的扑克牌例子
如果让你实现一个简单的扑克牌程序,代码可能是这样的(此处假定没有王,只有52张牌,4种花色):
// 牌类,有花色和大小两个属性 public class Card { private String color; private String num; public Card(String color, String num) { this.color = color; this.num = num; } public String printMsg() { return "扑克牌【" + color + num +"】"; } } // 测试用例 public class Player { public static void main(String[] args) { String[] colors = new String[]{"黑桃", "红心", "梅花", "方块"}; List<Card> cards = new ArrayList<>(); for (String color : colors) { for (int i = 1; i <= 13; i++) { switch (i) { case 11: cards.add(new Card(color, "J")); break; case 12: cards.add(new Card(color, "Q")); break; case 13: cards.add(new Card(color, "K")); break; default: cards.add(new Card(color, i + "")); break; } } } System.out.println("扑克牌初始完毕,共" + cards.size() + "张"); System.out.println("随机派五张牌:"); for (int i = 0; i < 5; i++) System.out.println(cards.get((int) (Math.random() * 52)).printMsg()); } }
运行输出结果如下:
网络异常,图片无法展示
|
正常输出,但却初始化了52个Card对象,,?如果用享元模式需要创建几个呢?
抽取下扑克牌的共有属性:花色和大小,花色固定四种,大小变化,写一个卡牌的父类,写四个花色子类继承:
// 享元类(抽象类或接口) abstract class AbstractCard { // 共享对象需实现的公共操作方法,使用一个外部状态作为输入参数(客户端保存,运行时改变) abstract String printMsg(String num); } // 具体享元类 class SpadeCard extends AbstractCard { @Override String printMsg(String num) { return "黑桃" + num; } } class HeartCard extends AbstractCard { @Override String printMsg(String num) { return "红心" + num; } } class SpadeCard extends AbstractCard { @Override String printMsg(String num) { return "黑桃" + num; } } class DiamondCard extends AbstractCard { @Override String printMsg(String num) { return "方块" + num; } } // 享元工厂 public class PokerFactory { public static final int SPADE = 0; // 黑桃 public static final int HEART = 1; // 红心 public static final int CLUB = 2; // 梅花 public static final int DIAMOND = 3; // 方块 public static Map<Integer, AbstractCard> pokers = new HashMap<>(); public static AbstractCard getPoker(int color) { // 直接拿,不用再调一次containsKey AbstractCard card = pokers.get(color); if(card == null) { System.out.println("花色对象不存在,新建对象..."); switch (color) { case SPADE: card = new SpadeCard(); break; case HEART: card = new HeartCard(); break; case CLUB: card = new ClubCard(); break; default: card = new DiamondCard(); break; } pokers.put(color, card); } else { System.out.println("花色对象已存在,复用对象..."); } return card; } } // 测试用例 public class Player { public static void main(String[] args) { for (int i = 0; i < 5; i++) { AbstractCard card; // 随机花色 switch ((int) (Math.random() * 4)) { case 0: card = PokerFactory.getPoker(PokerFactory.SPADE); break; case 1: card = PokerFactory.getPoker(PokerFactory.HEART); break; case 2: card = PokerFactory.getPoker(PokerFactory.CLUB); break; default: card = PokerFactory.getPoker(PokerFactory.DIAMOND); break; } // 随机大小 int num = (int)(Math.random() * 13 + 1); switch (num) { case 11: System.out.println(card.printMsg("J")); break; case 12: System.out.println(card.printMsg("Q")); break; case 13: System.out.println(card.printMsg("K")); break; default: System.out.println(card.printMsg(num + "")); break; } } } }