1 定义
享元模式就是:运用共享技术有效地支持大量细粒度的对象。
2 内部状态与外部状态
- 内部状态:在享元对象内部并且不会随环境改变而改变的共享部分。
- 外部状态:随环境改变而改变的、不可以共享的状态。
享元模式Flyweight执行时所需的状态有内部的也有外部的,内部状态存储于ConcreteFlyweight对象中,外部状态则应该考虑有客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。
3 适用场景
- 如果一个程序使用了大量的对象,而大量的这些对象造成了很大的开销时就应该考虑使用。
- 对象的大多数状态是外部状态,如果删除对象的外部状态,就可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
- 实际中,使用实例
- 这段代码返回值是true,如果每次创建新字符串对象时,都需要创建一个新的字符串对象的话,内存开销会很大。所以第一个创建了字符串对象str1,下次在创建相同的字符串str2时只需要把它的引用指向“大话设计模式”,这样就实现了“大话设计模式”在内存中的共享。
String str1="大话设计模式"; String str2="大话设计模式"; if(str1==str2) System.out.println(true);
- 五子棋
围棋的颜色是棋子的内部状态,位置是棋子的外部状态。一盘棋上有361个空位可以放棋子,那常规的面向对象方式编程,每盘棋可能有两三百个棋子对象产生。如果是有那个了享元模式来处理棋子,那么棋子对象可以减少到只有2个实例。
4 UML
5 优点和缺点
5.1 优点
可以避免大量细粒度的对象,解决了对象开销的问题,同时又不影响客户程序。因为用了享元模式,就有了共享对象,实例总数就大大减少了,如果共享的对象越多,存储节约就越多,节约量随着共享状态的增多而增大。
5.2 缺点
- 使用享元模式需要维护一个记录了系统已有的所有享元的列表。
- 享元模式使得系统更加复杂。
- 为了使得对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
因此,应该在有足够多的对象实例可供共享时才值得使用享元模式。
6 例子
6.1 场景
根据用户登录网站的类型,创建网站实例,从而同一类型的网站只存在一个实例。
6.2 UML
这里写图片描述
6.3 代码
Main
public class Main {
public static void main(String[] args) {
WebSiteFactory factory = new WebSiteFactory();
ConcreteWebSite web1 = (ConcreteWebSite)factory.getWebSite("产品展示");
web1.display(new User("李阳"));
ConcreteWebSite web2 = (ConcreteWebSite)factory.getWebSite("合作商家");
web2.display(new User("周青"));
ConcreteWebSite web3 = (ConcreteWebSite)factory.getWebSite("经销商信息");
web3.display(new User("黎洲"));
ConcreteWebSite web4 = (ConcreteWebSite)factory.getWebSite("合作商家");
web4.display(new User("李丽莉"));
}
}
User
public class User {
private String name;
public User(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
WebSite
public abstract class WebSite {
public abstract void display(User user);
}
ConcreteWebSite
public class ConcreteWebSite extends WebSite {
private String webType ="";
public ConcreteWebSite (String webType){
this.webType =webType;
}
@Override
public void display(User user) {
System.out.println("网站分类:"+ webType +" 用户:"+user.getName());
}
}
WebSiteFactory
public class WebSiteFactory {
private Hashtable<String, WebSite> hashtable=new Hashtable<>();
public WebSite getWebSite(String webType){
if(!hashtable.contains(webType)){
hashtable.put(webType,new ConcreteWebSite(webType));
}
return hashtable.get(webType);
}
public int getWebSiteCount(){
return hashtable.size();
}
}
运行结果
网站分类:产品展示 用户:李阳
网站分类:合作商家 用户:周青
网站分类:经销商信息 用户:黎洲
网站分类:合作商家 用户:李丽莉