设计模式使用场景实现示例及优缺点(结构型模式——享元模式)

avatar
作者
猴君
阅读量:3

国度的东南角,有一个被称为“享元村”的小村庄。村里的居民都是非常聪明的软件设计师,他们擅长用一种叫做“享元模式”的技术来解决内存使用问题。享元模式的核心思想是共享:通过共享来支持大量的细粒度对象的使用,从而在不牺牲程序性能的情况下,有效地减少内存的使用。

有一天,享元村的村长召集了所有村民,讲述了一个即将到来的挑战。“我们将接手一个非常大的项目,”村长说,“这个项目中有成千上万的用户和同样多的数据对象需要处理。我们必须找到一种方式来优化我们的程序,以便它能在不增加更多内存的情况下,高效地运行。”

所有的村民都聚在一起,开始讨论解决方案。他们决定利用享元模式,创建一个‘对象池’,这个池子里存放着所有可以共享的对象。每当程序需要一个新的对象时,它首先检查对象池中是否已经有一个相似的对象。如果有,程序就会重用这个对象;如果没有,它们才会创建一个新的对象并将其添加到池中。

结构型模式

享元模式(Flyweight Pattern)

享元模式,作为软件设计模式中的一员,其核心目标在于通过共享来有效地支持大量细粒度对象的使用。在内存使用优化方面,享元模式提供了一种极为高效的路径,尤其在处理大量对象且这些对象中多数属性相同的情况下表现得尤为突出。

享元模式的基本概念与应用

享元模式基于一个简单的理念:分离变与不变,共享不变,独立变化。具体到实现上,享元模式通常涉及到两个主要的组成部分——享元对象和享元工厂。享元对象中包含的状态可以分为内部状态和外部状态,其中内部状态是可以共享的不变状态,而外部状态则由具体的使用场景决定,不能共享。

内部状态(Intrinsic State):如字符代码的字体、大小等属性,这些属性对于同种类型的对象来说是共有的。

外部状态(Extrinsic State):如字符在文档中的位置,这些状态根据具体的使用场景会有所不同。

使用享元模式的典型场景包括处理大量相似对象时,这些对象由于其数量或复杂度会消耗大量内存资源。例如,在文本编辑器中,每个字符可以是一个对象;而字符的字体、大小可以是内部状态,字符的位置和颜色可以是外部状态。

适用场景

  1. 大量对象

    • 当应用程序使用了大量的对象,且这些对象因为数量巨大而造成很高的内存开销时。
  2. 可重复使用对象的状态

    • 对象的大多数状态都可以变为外部状态,也就是说,对象状态可以由其使用的上下文来决定。
  3. 细粒度对象

    • 应用程序不依赖于对象身份。由于享元对象可以被共享,对于概念上明显有别的对象,标识测试会返回真。

结构

享元模式包含以下几个核心角色:

享元工厂(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<String, Flyweight> 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");     } } 

优点

  1. 减少对象的创建

    • 享元模式可以极大地减少系统中对象的数量,降低系统内存的消耗,提高效率。
  2. 外部状态独立

    • 外部状态相对独立,不影响内部状态,使得享元对象可以在不同的环境中被共享。

缺点

  1. 复杂性增加

    • 使系统设计更加复杂,需要将对象的状态外部化,分离内部和外部状态,使得程序的逻辑复杂化。
  2. 线程安全问题

    • 在多线程环境下,共享的享元对象可能会引起线程安全问题,需要进行适当的同步处理。

类图

Client   |   v FlyweightFactory ----> Flyweight <---- ConcreteFlyweight 

总结

享元模式是一种结构型设计模式,它通过共享技术有效地支持大量细粒度对象的使用,适用于那些需要优化内存使用且对象数量巨大的系统。通过合理的使用享元模式,开发者可以在性能和资源利用之间找到一个良好的平衡点。然而,设计和实现享元模式需要仔细考虑如何分离内部状态和外部状态,确保系统的高效运行同时,也要注意不增加过多的运行时负担。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!