一、模式动机
享元模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。
二、模式定义
享元模式(Flyweight):运用共享技术有效地支持大量细粒度的对象。 系统只使用少量的对象,而这些对象都很近,状态变化很小,对象使用次数增多。享元模式是一种对象结构型模式。
三、模式结构
四、参与者
- Flyweight:抽象享元类
- ConcreteFlyweight:具体享元类
- UnsharedConcreteFlyweight:非共享具体享元类
- FlyweightFactory:享元工厂类
- Client:客户类
五、示例代码
package design.pattern;
import java.util.Hashtable;
abstract class Game {
public abstract void play();
}
class ConcreteGame extends Game {
private String name;
public ConcreteGame(String name) {
this.name = name;
}
public void play() {
System.out.println("运行游戏: " + name);
}
}
class GameFactory {
private Hashtable<String, Game> flyweights = new Hashtable<>();
public Game getGameCategory(String key) {
if (!flyweights.contains(key))
flyweights.put(key, new ConcreteGame(key));
return flyweights.get(key);
}
public int getGameCount() {
return flyweights.size();
}
}
public class Flyweight {
public static void main(String[] args) {
GameFactory f = new GameFactory();
Game zs = f.getGameCategory("斗地主");
zs.play();
Game ls = f.getGameCategory("斗地主");
ls.play();
Game ww = f.getGameCategory("斗地主");
ww.play();
Game zl = f.getGameCategory("打麻将");
zl.play();
Game sq = f.getGameCategory("打麻将");
sq.play();
Game zb = f.getGameCategory("打麻将");
zb.play();
System.out.println("游戏总数为 " + f.getGameCount());
}
}
- 模式结构
六、扩展
内部状态与外部状态
- 实现了享元模式共享的目的,无论几个用户,运行游戏一样,就只保留一个游戏逻辑代码
- 但是,这些用户毕竟不是同一个用户,用户名不同,用户的牌也不同
- 我们称享元对象内部不随环境变化的共享部分称为内部状态
- 而随环境而改变,不可以共享的称为外部状态
示例代码
package design.pattern;
import java.util.Hashtable;
// 用户
class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 游戏
abstract class Game {
public abstract void play(User user);
}
// 具体的游戏
class ConcreteGame extends Game {
private String name;
public ConcreteGame(String name) {
this.name = name;
}
public void play(User user) {
System.out.println("运行游戏: " + name + " 用户: " + user.getName());
}
}
class GameFactory {
private Hashtable<String, Game> flyweights = new Hashtable<>();
public Game getGameCategory(String key) {
if (!flyweights.contains(key))
flyweights.put(key, new ConcreteGame(key));
return flyweights.get(key);
}
public int getGameCount() {
return flyweights.size();
}
}
public class Flyweight {
public static void main(String[] args) {
GameFactory f = new GameFactory();
Game zs = f.getGameCategory("斗地主");
zs.play(new User("张三"));
Game ls = f.getGameCategory("斗地主");
ls.play(new User("李四"));
Game ww = f.getGameCategory("斗地主");
ww.play(new User("王五"));
Game zl = f.getGameCategory("打麻将");
zl.play(new User("赵六"));
Game sq = f.getGameCategory("打麻将");
sq.play(new User("孙七"));
Game zb = f.getGameCategory("打麻将");
zb.play(new User("周八"));
System.out.println("游戏总数为 " + f.getGameCount());
}
}
模式结构
优缺点
享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:享元模式使得系统更加复杂。
为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
模式使用
- 一个系统有大量的对象,造成耗费大量的内存。
- 这些对象的状态中的大部分都可以外部化。
- 这些对象可以按照内部状态分成很多的组,当把外部对象从对象中剔除时,每一个组都可以用相对较少的共享对象代替。
- 软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。