1、定义
(Flyweight)运用共享技术有效地支持大量细粒度的对象。
2、使用场景
如果要做三个产品展示、三个博客的网站,相当于是六个网站类的实例,每一个网站都需要一个对应的服务器资源,而本质上他们都是同一套代码,如果网站增多,实例也就随着增多,这对服务器的资源浪费得很严重,而且都不是属于高访问量的网站,如果整合到一个网站中,共享其相关的代码和数据,那么对于服务器资源都可以达成共享,减少服务器资源,而对于代码,由于是一份实例,维护和扩展都更加容易。
3、代码结构UML图
用户:用户 类,用于网站的客户账号,是”网站“类的外部状态
网站:抽象类所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
网站工厂:一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)
具体网站:继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。也可以指那些不需要共享的Flyweight子类。因为Flyweight接口成为可能,因为它并不强制共享。
4、类的实现
(1)、User(用户类,用于网站的客户账号,是"网站"类的外部状态)
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
(2)、Website (网站抽象类)
public abstract class Website {
public abstract void use(User user);
}
(3)、ConcreteWebsite (具体网站)
public class ConcreteWebsite extends Website {
private String name="";
public ConcreteWebsite(String name) {
this.name = name;
}
@Override
public void use(User user) {
System.out.println("网站分类:"+name+" 用户:"+user.getName());
}
}
(4)、WebsiteFactory (网站工厂类)
public class WebsiteFactory {
private Hashtable flyweights = new Hashtable();
public Website getWebsiteCategory(String key) {
if (!flyweights.containsKey(key)) {
flyweights.put(key, new ConcreteWebsite(key));
}
return (Website) flyweights.get(key);
}
//获得网站分类总数
public int getWebsiteCount() {
return flyweights.size();
}
}
5、客户端调用
public static void main(String[] args) {
WebsiteFactory f = new WebsiteFactory();
Website fx = f.getWebsiteCategory("产品展示");
fx.use(new User("小明"));
Website fx2 = f.getWebsiteCategory("产品展示");
fx2.use(new User("小王"));
Website fx3 = f.getWebsiteCategory("产品展示");
fx3.use(new User("小花"));
Website fx4 = f.getWebsiteCategory("博客");
fx4.use(new User("小黑"));
Website fx5 = f.getWebsiteCategory("博客");
fx5.use(new User("小吴"));
Website fx6 = f.getWebsiteCategory("博客");
fx6.use(new User("小红"));
System.out.println("获取网站分类总数:" + f.getWebsiteCount());
}
输出:
6、总结
享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上相同的,有时候能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将他们传递进来,就可以通过共享大幅度地减少单个实例的数目。
如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多数组对象,此时可以考虑使用享元模式。
参考:《大话设计模式》