目录
享元模式定义
运用共享技术有效地支持大量细粒度的对象。白话就是当系统中存在大量重复对象,而且这些对象是不可变的,我们就可以利用享元模式将对象设计为享元,在内存中只留一份实例,供多处引用。
优点
-
减少内存占用:通过内部共享状态,减少对象数量,从而降低内存占用。
-
提高性能:减少对面的数量可以提高程序的性能,因为创建和销毁对象通常是昂贵的操作。
-
支持大规模对象:适用于需要管理大规模对象的场景 。
缺点
-
增加复杂性:引入享元模式可能会增加代码的复杂性,因为需要维护享元工厂和池。
-
外部状态管理:外部状态需要客户端管理,这会导致一些复杂性和错误。
享元模式结构说明
-
享元(Flyweight):享元是模式的核心,它包含了共享的状态,这些状态可以在多个对象之间共享。享元对象必须是不可变的,以确保共享的状态不会被修改。
-
具体享元(ConcreteFlyweight):具体享元是享元接口的实现,它包含了特定于每个对象的内部状态。这些对象可以被多个上下文共享。
-
享元工厂(FlyweightFactory):享元工厂负责创建和管理享元对象,它维护一个享元池(或缓存),用于存储和获取已经创建的享元对象。如果请求的享元对象已经存在,工厂返回现有对象,否则,它创建一个新的享元对象。
工作流程
-
客户端通过享元工厂请求享元对象。
-
享元工厂检查是否已经存在具有相同状态的享元对象。
-
如果存在,工厂返回现有的享元对象;如果不存在,工厂创建一个新的享元对象并将其添加到享元池中。
-
客户端使用享元对象,通常通过传递一些外部状态给享元对象,以补充其内部状态。
-
客户端可以多次使用不同的外部状态来操作相同的享元对象。
场景示例
最近快中秋了,月饼厂生产月饼,圆形的有直径5cm、6cm的,需要新增正方形的,边长6cm、8cm的。
代码练习
1.创建抽象享元接口Cake,定义一个行为show()。参数Size就是享元模式中享元对象的外部状态。
public interface Cake { void show(String size); }
2.创建具体的享元对象MoonCake,内部状态定义为shape。
public class MoonCake implements Cake { private String shape; public MoonCake(String shape){ this.shape = shape; } public void show (String size){ System.out.println("Object Adress:" + System.identityHashCode(this)); System.out.println("月饼:" + shape + size); } }
3.创建享元对象工厂,管理享元对象的创建和获取。
public class MoonCakeFactory { private HashMap<String, Cake> cakes = new HashMap<>(); public Cake getCake(String shape) { if(!cakes.containsKey(shape)){ MoonCake moonCake = new MoonCake(shape); cakes.put(shape, mooncake); } return cakes.get(shape) } }
4.客户端通过享元工厂获取内部状态一致的对象,设置外部状态展示对象。
public class Client { public static void main(String[] args) { MoonCakeFactory moonCakeFactory = new MoonCakeFactory(); Cake moonCake = moonCakeFactory.getCake("圆形"); moonCake.show("直径6cm"); Cake moonCake1 = moonCakeFactory.getCake("圆形"); moonCake1.show("直径8cm"); } }
应用场景
当需要创建大量相似对象并且这些对象可以共享一些相同的状态时候,享元模式非常有用。比如文字处理软件中的字符和字体管理。
本质
享元模式的本质是分离对象的内部状态和外部状态,通过共享内部状态来减少对象的数量,从而降低内存开销和提高性能。
涉及的设计原则
组合/聚合复用原则:享元模式的主要目标是共享对象,以便在系统中复用它们,而不是频繁地创建对象。
相关设计模式
-
工厂模式:享元模式通常与工厂模式一起使用,享元工厂负责创建对象和管理对象。
-
单例模式:单例模式与享元模式结合可以实现全局共享的对象池。
开源框架中的示例
-
典型的java.lang.String类就是享元模式的一个例子。字符串常量池中存储了字符对象的共享实例,这些实例可以被多个字符引用,以节省内存。
-
java中的Integer和Long类的缓存也是享元模式的应用,在范围内共享相同的对象以减少内存的使用。