享元模式
享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。
享元模式的核心思想其实就是共享,节省内存,减少开销,例如项目中的对象共享,利用享元工厂维护已经创建的或者预先创建的对象,当需要时再去该工厂里拿即可。
享元对象状态分为内部状态和外部状态。引用大话设计模式的一段话,清楚地理解内部状态和外部状态的区别。
享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,就能够大幅度地减少需要实例化的类的数量。如果能把这些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。
还是举例来说明,假设网站包括博客系统和在线书店两种类型,博客和在线书店都是网站,网站是通过用户账号登录的。因此用户账号就是网站的外部状态,那么网站的内部状态是什么呢?其实就是博客和在线书店本身,看下类图:
UML类图
WebSite作为网站抽象基类,通过方法参数传入用户,作为网站的外部状态。ConcreteWebSite实现了WebSite抽象基类,并提供了私有字段type-网站类型作为网站的内部状态。FlyweightFactory作为享元工厂提供了共享对象的存储和获取,接着看代码实现。
代码实现
首先看下网站抽象基类WebSite
WebSite
/**
* <p>文件描述: 网站抽象类</p>
*
* @Author luanmousheng
* @Date 17/11/12 下午10:39
*/
public abstract class WebSite {
abstract void use(User user);
}
用户类
User
/**
* <p>文件描述: 用户类</p>
*
* @Author luanmousheng
* @Date 17/11/12 下午10:53
*/
public class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
具体网站类
ConcreteWebSite
/**
* <p>文件描述: 具体网站类</p>
*
* @Author luanmousheng
* @Date 17/11/12 下午10:42
*/
public class ConcreteWebSite extends WebSite {
//网站类型,eg: blog、book_shop
private String type;
public ConcreteWebSite(String type) {
this.type = type;
}
@Override
public void use(User user) {
System.out.println("user: " + user.getName() + " use web type: " + type);
}
}
享元工厂类
FlyweightFactory
/**
* <p>文件描述: 享元工厂</p>
*
* @Author luanmousheng
* @Date 17/11/12 下午10:47
*/
public class FlyweightFactory {
//存储共享对象,网站类型为key
private HashMap<String, WebSite> flyweights = new HashMap<>();
public WebSite getWebSite(String type) {
if (type == null) {
throw new IllegalArgumentException("param is null");
}
if (!flyweights.containsKey(type)) {
flyweights.put(type, new ConcreteWebSite(type));
}
return flyweights.get(type);
}
}
测试类
FlyweightDemo
/**
* <p>文件描述: 享元模式Demo</p>
*
* @Author luanmousheng
* @Date 17/11/12 下午10:48
*/
public class FlyweightDemo {
public static void main(String[] args) {
FlyweightFactory flyweightFactory = new FlyweightFactory();
WebSite blogWeb = flyweightFactory.getWebSite("blog");
blogWeb.use(new User("tom", 23));
blogWeb.use(new User("linda", 19));
WebSite bookShopWeb = flyweightFactory.getWebSite("book_shop");
bookShopWeb.use(new User("jack", 20));
}
}
测试类输出结果:
user: tom use web type: blog
user: linda use web type: blog
user: jack use web type: book_shop
测试结果显示共享了类型为blog的网站。
享元模式的思路很简单,但是作用确不简单。系统共享对象较多时可以考虑使用该模式,否则引入享元模式只会增加代码的复杂度,得不偿失。
参考
- 大话设计模式 程杰