运用共享技术来有効地支持大量细粒度对象的复用。享元对象的两个状态:内部状态和外部状态。
角色
抽象享元(Flyweight):接口或抽象类,定义可共享的内部状态和公共接口,不可共享的外部状态(非享元)作为接口参数的方式传入
具体享元(Concrete Flyweight):实现抽象享元角色中所规定的接口
非享元(Unsharable Flyweight):不可以共享的外部状态,以参数的形式传入享元的接口
享元工厂(Flyweight Factory):负责创建和管理享元角色。先检查缓存中是否存在符合要求的享元对象,如果存在直接返回,不存在创建新的享元对象
抽象享元 Flyweight
抽象方法,定义可共享的内部状态,公共接口
public abstract class Flyweight {
protected String innerStatus;
public Flyweight(String innerStatus) {
this.innerStatus = innerStatus;
}
abstract void operation(UnsharedConcreteFlyweight outerStatus);
}
具体享元 Concrete Flyweight
继承享元基类,实现公共接口
public class ConcreteFlyweight extends Flyweight {
public ConcreteFlyweight(String innerStatus) {
super(innerStatus);
}
@Override
public void operation(UnsharableConcreteFlyweight outerStatus) {
System.out.print(", inner status: " + innerStatus);
System.out.println(", outer status: " + outerStatus);
}
}
非享元 Unsharable Flyweight
定义不可共享的外部状态
public class UnsharableConcreteFlyweight {
private String info;
public UnsharedConcreteFlyweight(String info) {
this.info = info;
}
@Override
public String toString() {
return info;
}
}
享元工厂 FlyweightFactory
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class FlyweightFactory {
private static final ConcurrentMap<String, Flyweight> flyweights = new ConcurrentHashMap<>();
public Flyweight getFlyweight(String innerStatus) {
if (flyweights.containsKey(innerStatus)) {
System.out.print(String.format("\tGet exist Flyweight: %s", innerStatus));
return flyweights.get(innerStatus);
}
Flyweight flyweight = new ConcreteFlyweight(innerStatus);
flyweights.put(innerStatus, flyweight);
System.out.print(String.format("Create new Flyweight: %s", innerStatus));
return flyweight;
}
}
测试类
public class FlyweightTester {
public static void main(String args[]) {
FlyweightFactory factory = new FlyweightFactory();
Random random = new Random();
String innerStatus;
UnsharableConcreteFlyweight outerStatus = null;
for (int i = 0; i < 5; i++) {
innerStatus = String.format("%5d", random.nextInt(2));
String uuid = UUID.randomUUID().toString().replace("-", "");
outerStatus = new UnsharableConcreteFlyweight(uuid);
factory.getFlyweight(innerStatus).operation(outerStatus);
}
}
}
Create new Flyweight: 1, inner status: 1, outer status: c057fe41093247f8bf92344fd5a25194
Create new Flyweight: 0, inner status: 0, outer status: cfbf38fedbe948d782a6b7efd32e2767
Get exist Flyweight: 1, inner status: 1, outer status: b40861ba38ea4272832e25c458ec4c9a
Get exist Flyweight: 1, inner status: 1, outer status: 4f03baf03cab4e219be84793d7500c1c
Get exist Flyweight: 0, inner status: 0, outer status: 2f769afc0290441a93af812e58d2b236
举例1:围棋
围棋分为黑子和白子,颜色仅两种,可共享作为内部状态,在棋盘的位置属于外部状态不可共享,在下棋时确认
public abstract class Chess {
abstract void drop(Coordinate coordinate);
}
public class ChessPiece extends Chess {
private Color color;
public ChessPiece(Color color) {
this.color = color;
}
public void drop(Coordinate coordinate) {
System.out.println(String.format("%s落在:%s", color.type(), coordinate.position()));
}
public enum Color {
White("白子"),
Black("黑子");
private String type;
Color(String type) {
this.type = type;
}
public String type() {
return type;
}
}
}
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public String position() {
return String.format("%2d, %2d", x, y);
}
}
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ChessPieceFactory {
public static final ConcurrentMap<ChessPiece.Color, ChessPiece> chessPieceCaches = new ConcurrentHashMap<>(2);
public static ChessPiece getChessPiece(ChessPiece.Color color) {
if (chessPieceCaches.containsKey(color)) {
return chessPieceCaches.get(color);
}
ChessPiece chessPiece = new ChessPiece(color);
chessPieceCaches.put(color, chessPiece);
return chessPiece;
}
}
public class ChessPieceTester {
public static void main(String args[]) {
ChessPiece whiteChessPiece = ChessPieceFactory.getChessPiece(ChessPiece.Color.White);
whiteChessPiece.drop(new Coordinate(1, 1));
ChessPiece blackChessPiece = ChessPieceFactory.getChessPiece(ChessPiece.Color.Black);
blackChessPiece.drop(new Coordinate(1, 2));
}
}
白子落在: 1, 1
黑子落在: 1, 2
举例2:麻将
四川麻将共108张,分为筒、条、万三种牌型,包含 1-9 数字,同一花色有4张,类型和数字可作为内部状态,而打牌的人属于外部状态
public class Mahjong implements Comparable<Mahjong> {
private Type type;
private Number number;
public Mahjong(Type type, Number number) {
this.type = type;
this.number = number;
}
public void play(String name) {
System.out.println(String.format("%s play %s %s", name, number, type));
}
public String getType() {
return type.getDesc();
}
public String getNumber() {
return number.getDesc();
}
public String getDescription() {
return String.format("%s%s", number.getDesc(), type.getDesc());
}
@Override
public int compareTo(Mahjong another) {
if (this.type.equals(another.type) && this.number.equals(another.number))
return 0;
if (this.type.compareTo(another.type) != 0) {
return this.type.compareTo(another.type);
}
return this.number.compareTo(another.number);
}
public enum Type {
TONG("筒"),
TIAO("条"),
WAN("万");
private String desc;
Type(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
public enum Number {
ONE("一"),
TWO("二"),
THREE("三"),
FOUR("四"),
FIVE("五"),
SIX("六"),
SEVEN("七"),
EIGHT("八"),
NINE("九");
private String desc;
Number(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
}
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class MahjongFactory {
private static final ConcurrentMap<String, Mahjong> mahjongCaches = new ConcurrentHashMap<>(27);
public static Mahjong getMahjong(Mahjong.Type type, Mahjong.Number number) {
String key = type.name() + "#" + number.name();
if (mahjongCaches.containsKey(key)) {
return mahjongCaches.get(key);
}
Mahjong newInstance = new Mahjong(type, number);
mahjongCaches.put(key, newInstance);
return newInstance;
}
}
import java.util.*;
public class Player {
private static final Random random = new Random((int) (Math.random() * 10));
private String name;
private List<Mahjong> mahjongs;
public Player(String name) {
this.name = name;
mahjongs = new ArrayList<>(13);
}
public void touchCard(Mahjong mahjong, boolean display) {
if (display) {
System.out.println(String.format("%s 摸牌,摸到: %s", name, mahjong.getDescription()));
}
mahjongs.add(mahjong);
Collections.sort(mahjongs);
if (display) {
display();
}
}
public void playCard() {
Iterator<Mahjong> iterator = mahjongs.iterator();
Mahjong mahjong = mahjongs.remove(random.nextInt(mahjongs.size() - 1));
System.out.println(String.format("%s 打出: %s", name, mahjong.getDescription()));
Collections.sort(mahjongs);
display();
}
public int cardCount() {
return mahjongs.size();
}
public void display() {
StringBuffer sb = new StringBuffer();
Iterator<Mahjong> iterator = mahjongs.iterator();
while (iterator.hasNext()) {
Mahjong mahjong = iterator.next();
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(mahjong.getDescription());
}
sb.insert(0, String.format("[%s] (%2d) ", name, cardCount()));
System.out.println(sb.toString());
}
}
public class MahjongMachine {
private static final Random random = new Random((int) (Math.random() * 10));
private static final Map<String, List<Mahjong>> mahjongCaches = new HashMap<>(27);
private List<Mahjong> mahjongs = new ArrayList<>();
public void touchCard(Player player) {
Iterator<Mahjong> iterator = mahjongs.iterator();
if (iterator.hasNext()) {
Mahjong mahjong = iterator.next();
player.touchCard(mahjong, true);
iterator.remove();
}
}
public List<Player> licensing(int cardCount, String ... playerNames) {
Player player = null;
List<Player> players = new ArrayList<>(playerNames.length);
for (String playerName : playerNames) {
player = new Player(playerName);
players.add(player);
}
int counter = 0, playerCount = playerNames.length;
Mahjong mahjong;
Iterator<Mahjong> iterator = mahjongs.iterator();
while (iterator.hasNext()) {
player = players.get(counter % playerCount);
if (player.cardCount() < cardCount + 1) {
mahjong = iterator.next();
player.touchCard(mahjong, false);
iterator.remove();
counter++;
if (player.cardCount() == cardCount + 1) {
break;
}
}
}
for (Player temp : players) {
temp.display();
}
return players;
}
public void reshuffle() {
List<Mahjong> result = new ArrayList<>(108);
for (Map.Entry<String, List<Mahjong>> entry : mahjongCaches.entrySet()) {
result.addAll(entry.getValue());
}
mahjongs.addAll(result);
Collections.shuffle(mahjongs);
}
public void init() {
if (mahjongCaches != null && !mahjongCaches.isEmpty()) {
return;
}
List<Mahjong> temp = null;
for (Mahjong.Type type : Mahjong.Type.values()) {
for (Mahjong.Number number : Mahjong.Number.values()) {
String key = String.format("%s#%s", type.name(), number.name());
for (int i = 0; i < 4; i++) {
if (!mahjongCaches.containsKey(key)) {
temp = new ArrayList<>(4);
temp.add(MahjongFactory.getMahjong(type, number));
mahjongCaches.put(key, temp);
} else if ((temp = mahjongCaches.get(key)).size() < 4) {
temp.add(MahjongFactory.getMahjong(type, number));
mahjongCaches.put(key, temp);
}
}
}
}
}
public int cardCount() {
return mahjongs.size();
}
private <T extends Enum<T>> T random(Class<T> tClass) {
if (!tClass.isEnum()) {
throw new RuntimeException("Class is not a enum: " + tClass.getName());
}
int bound = Mahjong.Type.values().length;
int randomIndex = random.nextInt(bound);
return tClass.getEnumConstants()[randomIndex];
}
}
import java.util.List;
public class MahjongTester {
public static void main(String args[]) {
MahjongMachine machine = new MahjongMachine();
machine.init();
machine.reshuffle();
int round = 1;
String[] playerNames = new String[] { "张三", "李四", "王二", "麻子" };
System.out.println("===============================================");
System.out.println(String.format(" 开始第%3d局 ", round));
System.out.println("===============================================");
List<Player> players = machine.licensing(12, playerNames);
System.out.println(String.format("剩余:%3d 张牌", machine.cardCount()));
int counter = 1, playerCount = playerNames.length;
System.out.println("\n");
Player player;
player = players.get(0);
player.playCard();
counter++;
while (machine.cardCount() > 0 && round <= 100) {
System.out.println("\n");
player = players.get(counter % playerCount);
machine.touchCard(player);
System.out.println(String.format("剩余:%3d 张牌", machine.cardCount()));
counter++;
player.playCard();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (machine.cardCount() == 0) {
System.out.println("Game Over!");
if (++round <= 100) {
System.out.println("===============================================");
System.out.println(String.format(" 开始第%3d局 ", round));
System.out.println("===============================================");
machine.reshuffle();
}
}
}
}
}
参考:
http://c.biancheng.net/view/1371.html
https://blog.csdn.net/Elsa15/article/details/87930541
https://www.cnblogs.com/V1haoge/p/6542449.html