享元模式是什么🌝
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。运用了共享技术有效的支持大量细粒度对象的重复利用,时较为轻量级的对象结构型模式。享元模式的产生背景例如,围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源。
享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两个部分:内部状态和外部状态。 内部状态指对象共享出来的信息,存储在享元信息内部,并且不回随环境的改变而改变;(例如String 缓存池) 外部状态指对象得以依赖的一个标记,随环境的改变而改变,不可共享。
享元模式能干什么🌝
在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。即系统有大量相似对象或者需要缓冲池的场景。
享元模式的优缺点🌝
优点
相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。
缺点
提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。读取享元模式的外部状态会使得运行时间稍微变长。
享元状态的角色组成部分🌝
辅助图示
示例代码
1、抽象享元角色
public interface Flyweight { void operation(UnsharedConcreteFlyweight state); }
2、具体享元角色
public class ConcreteFlyweight implements Flyweight{ private String key; ConcreteFlyweight(String key) { this.key = key; System.out.println("具体享元" + key + "被创建!"); } @Override public void operation(UnsharedConcreteFlyweight outState) { System.out.print("具体享元" + key + "被调用,"); System.out.println("非享元信息是:" + outState.getInfo()); } }
3、非享元角色
public class UnsharedConcreteFlyweight { private String info; UnsharedConcreteFlyweight(String info) { this.info = info; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
4、享元工厂
public class FlyweightFactory { private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>(); public Flyweight getFlyweight(String key) { Flyweight flyweight = (Flyweight) flyweights.get(key); if (flyweight != null) { System.out.println("具体享元" + key + "已经存在,被成功获取!"); } else { flyweight = new ConcreteFlyweight(key); flyweights.put(key, flyweight); } return flyweight; } }
5、Client
public class TestClient { public static void main(String[] args) { FlyweightFactory factory = new FlyweightFactory(); //想要的对象在享元池则直接拿,没有则创建放入享元池中 Flyweight f01 = factory.getFlyweight("a"); Flyweight f02 = factory.getFlyweight("a"); Flyweight f03 = factory.getFlyweight("a"); Flyweight f11 = factory.getFlyweight("b"); Flyweight f12 = factory.getFlyweight("b"); System.out.println("--------带状态的非享元调用-------"); //非享元角色为享元角色的外部状态 f01.operation(new UnsharedConcreteFlyweight("a加上绿色")); f02.operation(new UnsharedConcreteFlyweight("a加上红色")); f03.operation(new UnsharedConcreteFlyweight("a加上白色")); f11.operation(new UnsharedConcreteFlyweight("b加上白色")); f12.operation(new UnsharedConcreteFlyweight("b加上蓝色")); } }
运行结果
具体享元a被创建! 具体享元a已经存在,被成功获取! 具体享元a已经存在,被成功获取! 具体享元b被创建! 具体享元b已经存在,被成功获取! --------带状态的非享元调用------- 具体享元a被调用,非享元信息是:a加上绿色 具体享元a被调用,非享元信息是:a加上红色 具体享元a被调用,非享元信息是:a加上白色 具体享元b被调用,非享元信息是:b加上白色 具体享元b被调用,非享元信息是:b加上蓝色