设计模式之享元模式学习笔记
前言
享元模式是池技术(String常量池、数据库连接池、缓冲池等)的重要实现方式,可以减少应用程序创建对象,降低程序内存的占用,提高性能。
定义
使用共享对象,有效的大量细粒度的对象
结构图
角色拆解分析:
1.Flyweight:抽象享元角色,同时定义出对象的外部和内部状态的接口或实现
2.ConcreteFlyweight:具体享元角色,实现Flyweight定义的业务
3.FlyweightFactory:享元工厂,负责管理对象池和创建享元对象
举栗实现
我们都知道京东618狂欢节,还有天猫双十一,卖的东西都很便宜(也有很多套路,比如先涨价再打折…)。“剁手党”们近乎疯狂的扫货,更有甚者不但“剁手”,还“剁脚”。每个人的订单都生成一个商品对象,那就直接Out Of Memory了。
1.Flyweight抽象享元角色
这是一个商品接口,定义了商品的价格标签
public interface IGoods {
public void showGoodPrice(String name);
}
2.ConcreteFlyweight具体享元角色
商品类实现IGoods接口,其中name为内部状态,version为外部状态(内部状态指对象共享出来的信息,存储在享元对象内部不会因为环境改变;外部状态指对象得以依赖的标记,随环境改变、不可共享)
public class Goods implements IGoods {
private String name;//商品名称,内部状态
private String version;//配置,外部状态
public Goods(String name) {
this.name = name;
}
@Override
public void showGoodPrice(String version) {
if (version.equals("乞丐版")){
System.out.print("便宜,没几个钱");
}else if (version.equals("顶配版")){
System.out.print("过万了");
}
}
}
3.FlyweightFactory享元工厂
创建商品对象,并以map来存储。将内部状态name作为key,如果存在就继续存,否则就创建新的
public class GoodsFactory {
private static HashMap<String,Goods> map = new HashMap<String,Goods>();
public static Goods getGoods(String name){
if (map.containsKey(name)){
System.out.print("商品对象存在,key为"+name);
return map.get(name);
}else {
Goods goods = new Goods(name);
map.put(name,goods);
System.out.print("创建商品对象,key为"+name);
return goods;
}
}
}
4.客户端调用
通过享元工厂的getGoods方法来创建对象,并调用Goods中的showGoodPrice方法来显示价格
public class EnjoyClient {
public static void main(String []args){
Goods hp = GoodsFactory.getGoods("暗影精灵");
hp.showGoodPrice("乞丐版");
Goods hp2 = GoodsFactory.getGoods("暗影精灵");
hp2.showGoodPrice("乞丐版");
Goods hp3 = GoodsFactory.getGoods("暗影精灵");
hp3.showGoodPrice("顶配版");
}
}
优缺点对比
优点:
减少了对象的创建,降低了程序内存的占用,提高效率
缺点:
提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变
使用场景
1.系统中存在大量的相似对象
2.需要缓冲池的场景
最后说一句
1.运用共享技术有效地支持大量细粒度对象的复用
2.享元工厂实际就做了两件事:维护享元池;提供一个遍历key返回对象的方法
3.从某种意义上来讲,享元模式就是单例模式+工厂模式