设计模式使用场景实现示例及优缺点(结构型模式——享元模式)
结构型模式
享元模式(Flyweight Pattern)
享元模式,作为软件设计模式中的一员,其核心目标在于通过共享来有效地支持大量细粒度对象的使用。在内存使用优化方面,享元模式提供了一种极为高效的路径,尤其在处理大量对象且这些对象中多数属性相同的情况下表现得尤为突出。
享元模式的基本概念与应用
享元模式基于一个简单的理念:分离变与不变,共享不变,独立变化。具体到实现上,享元模式通常涉及到两个主要的组成部分——享元对象和享元工厂。享元对象中包含的状态可以分为内部状态和外部状态,其中内部状态是可以共享的不变状态,而外部状态则由具体的使用场景决定,不能共享。
内部状态(Intrinsic State):如字符代码的字体、大小等属性,这些属性对于同种类型的对象来说是共有的。
外部状态(Extrinsic State):如字符在文档中的位置,这些状态根据具体的使用场景会有所不同。
使用享元模式的典型场景包括处理大量相似对象时,这些对象由于其数量或复杂度会消耗大量内存资源。例如,在文本编辑器中,每个字符可以是一个对象;而字符的字体、大小可以是内部状态,字符的位置和颜色可以是外部状态。
适用场景
-
大量对象:
- 当应用程序使用了大量的对象,且这些对象因为数量巨大而造成很高的内存开销时。
-
可重复使用对象的状态:
- 对象的大多数状态都可以变为外部状态,也就是说,对象状态可以由其使用的上下文来决定。
-
细粒度对象:
- 应用程序不依赖于对象身份。由于享元对象可以被共享,对于概念上明显有别的对象,标识测试会返回真。
结构
享元模式包含以下几个核心角色:
享元工厂(Flyweight Factory):
负责创建和管理享元对象,通常包含一个池(缓存)用于存储和复用已经创建的享元对象。
具体享元(Concrete Flyweight):
实现了抽象享元接口,包含了内部状态和外部状态。内部状态是可以被共享的,而外部状态则由客户端传递。
抽象享元(Flyweight):
定义了具体享元和非共享享元的接口,通常包含了设置外部状态的方法。
客户端(Client):
使用享元工厂获取享元对象,并通过设置外部状态来操作享元对象。客户端通常不需要关心享元对象的具体实现。
实现示例(Java)
以下是一个简单的享元模式的实现示例,展示如何利用共享技术来管理字符的实例。
1. 定义享元接口
public interface Flyweight { void operation(String extrinsicState); }
2. 创建具体享元类
public class ConcreteFlyweight implements Flyweight { private String intrinsicState; public ConcreteFlyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } public void operation(String extrinsicState) { System.out.println("Intrinsic State = " + intrinsicState + ", Extrinsic State = " + extrinsicState); } }
3. 创建享元工厂类
import java.util.HashMap; import java.util.Map; public class FlyweightFactory { private Map flyweights = new HashMap(); public Flyweight getFlyweight(String key) { if (!flyweights.containsKey(key)) { flyweights.put(key, new ConcreteFlyweight(key)); } return flyweights.get(key); } }
4. 客户端代码
public class Client { public static void main(String[] args) { FlyweightFactory factory = new FlyweightFactory(); Flyweight flyweightA = factory.getFlyweight("A"); Flyweight flyweightB = factory.getFlyweight("B"); Flyweight flyweightA2 = factory.getFlyweight("A"); flyweightA.operation("First Call"); flyweightB.operation("Second Call"); flyweightA2.operation("Third Call"); } }
优点
-
减少对象的创建:
- 享元模式可以极大地减少系统中对象的数量,降低系统内存的消耗,提高效率。
-
外部状态独立:
- 外部状态相对独立,不影响内部状态,使得享元对象可以在不同的环境中被共享。
缺点
-
复杂性增加:
- 使系统设计更加复杂,需要将对象的状态外部化,分离内部和外部状态,使得程序的逻辑复杂化。
-
线程安全问题:
- 在多线程环境下,共享的享元对象可能会引起线程安全问题,需要进行适当的同步处理。
类图
Client | v FlyweightFactory ----> Flyweight