一、前言
本篇主题为结构型模式中的第六个模式–享元模式。上篇 Java 设计模式主题为 《Java 设计模式之外观模式(十)》 。
二、简单介绍
2.1 定义
享元(Flyweight)模式是构造型模式之一, 它通过与其他类似对象共享数据来减小内存占用。
2.2 参与角色
抽象享元:所有具体享元类的父类,规定一些需要实现的公共接口,可接收外部状态。
具体享元:抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法并存储内部状态。
享元工厂:负责创建和管理享元角色。
2.3 应用场景
一个应用程序使用了大量的对象。
由于使用大量的对象,造成很大的存储开销。
对象的大多数状态都可变为外部状态。
其中,在享元对象内部并不会随环境变化而改变的共享部分,称为内部状态。反之,随环境改变而改变的、不可以共享的状态称为外部状态。
三、实现方式
以网站为例,小明是个自由职业者,在网上专门帮人完成软件设计(网站后台管理系统)需求。
在不使用享元模式时,通过代码实现上述场景需求:
网站系统:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class WebSite {
private String name;
public WebSite(String name) { super(); this.name = name; } public void show() { System.out.println(this.name); } }
|
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Client {
public static void main(String[] args) { WebSite ws1 = new WebSite("A后台管理系统"); WebSite ws2 = new WebSite("B后台管理系统"); ws1.show(); ws2.show(); } }
|
打印结果:
从代码上看,当有 N 家公司找小明做后台管理系统时,小明需要编写 N 次代码。假设某一个系统出现 bug,意味着需要维护 N 个系统的代码,维护量很大。因此,上边的代码实现方案不可取。
用过后台管理系统的网友都知道,后台系统的功能大同小异,页面的结构和展示可以相同(内部状态),不同之处在于公司业务需求(外部状态)。
现在,我们使用享元模式实现:
外部状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class User {
private String name;
public User(String name) { super(); this.name = name; }
public String getName() { return name; }
}
|
抽象享元:
1 2 3 4 5 6
| public abstract class WebSite { // 内部状态 protected String name; public abstract void show(User user); }
|
具体享元:
1 2 3 4 5 6 7 8 9 10 11 12
| class WebSiteA extends WebSite {
public WebSiteA(String name) { this.name = name; } @Override public void show(User user) { System.out.println(user.getName() + "的" + this.name); } }
|
享元工厂:
1 2 3 4 5 6 7 8 9 10 11
| public class WebSiteFactory {
private static Map<String,WebSite> map = new HashMap<String,WebSite>(); public static WebSite getWebSite(String type) { if (!map.containsKey(type)) { map.put(type, new WebSiteA(type)); } return map.get(type); } }
|
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Client {
public static void main(String[] args) { WebSite ws1 = WebSiteFactory.getWebSite("后台管理系统"); WebSite ws2 = WebSiteFactory.getWebSite("后台管理系统"); System.out.println(ws1 == ws2); ws1.show(new User("A 公司")); ws2.show(new User("B 公司")); } }
|
打印结果:
1 2 3
| true A 公司的后台管理系统 B 公司的后台管理系统
|
从结果可知,两家公司通用一套系统模板,很大的节省了小明的开发量和维护量。
总结:享元模式可以避免大量非常相似的类开销。
UML 类图表示如下: