设计模式之享元模式

avatar
作者
猴君
阅读量:2

设计模式之享元模式(Flyweight Pattern)是一种结构型设计模式,其核心思想是通过共享技术来支持大量细粒度对象的复用,从而减少对象的创建数量,降低内存消耗,提高应用程序的性能和资源利用率。以下是对享元模式的详细介绍:

一、定义与特点

  • 定义:享元模式运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似类的开销,从而提高系统资源的利用率。
  • 特点
    • 细粒度对象:享元模式通常应用于系统中存在大量细粒度对象的场景。
    • 共享技术:通过共享技术来减少对象的数量,从而降低内存消耗。
    • 内外状态分离:享元模式将对象的状态分为内部状态和外部状态。内部状态是不变的,可以在多个对象之间共享;外部状态是随环境改变而改变的,不能共享。

二、类图结构与角色

享元模式的实现通常包括以下几个部分:

  1. 享元接口(Flyweight Interface):定义一个接口,用于声明享元对象的方法。
  2. 具体享元类(Concrete Flyweights):实现享元接口,为内部状态提供存储空间。
  3. 非共享具体享元类(Unshared Concrete Flyweights):那些不需要共享的享元子类。
  4. 享元工厂类(Flyweight Factory):用于创建并管理享元对象。它维护一个享元池,根据需要提供共享对象,避免无限制地创建新对象。

三、主要优点

  1. 减少内存消耗:通过共享相同或相似的对象,可以显著减少内存中对象的数量,降低内存消耗。
  2. 提高性能:减少了对象的创建和销毁时间,从而提高了系统的性能。
  3. 加强数据共享:强化了对象间的数据共享,有助于统一管理和减少冗余数据。

四、主要缺点

  1. 增加程序复杂性:为了使对象可以共享,需要将一些不能共享的状态外部化,这增加了程序的复杂性。
  2. 运行时间变长:读取享元模式的外部状态可能会使运行时间稍微变长。
  3. 线程安全问题:在多线程环境下使用享元对象时,需要考虑线程安全的问题。

五、适用场景

享元模式适用于以下场景:

  1. 系统中存在大量相似对象:当系统需要创建大量相似对象时,可以考虑使用享元模式来减少内存消耗。
  2. 对象的创建成本较高:如果对象的创建成本较高,且对象的状态可以分为内部状态和外部状态时,可以使用享元模式来减少创建对象的数量。
  3. 需要精细化控制对象共享:当需要对对象的共享进行精细化控制时,可以使用享元模式通过享元工厂来管理对象的创建和共享。

六、示例

下面是一个简单的Java享元模式例子,我们将创建一个简单的图形系统,其中包含多种图形(如圆形、矩形等),但每个图形都有多种颜色。由于颜色的种类可能非常多,而每种颜色可能对应多个图形,因此我们可以使用享元模式来共享颜色对象,以减少内存使用。

首先,我们定义一个Color类作为内部状态(可以共享),和一个Shape接口以及具体的Shape类作为外部状态(不可共享)。然后,我们创建一个ShapeFactory类来管理Shape对象的创建,并确保颜色的共享。

// Color 类,代表内部状态,可以共享   class Color {       private String color;          public Color(String color) {           this.color = color;       }          public String getColor() {           return color;       }          // 假设我们有一个简单的equals方法来检查颜色是否相同       @Override       public boolean equals(Object obj) {           if (this == obj) return true;           if (obj == null || getClass() != obj.getClass()) return false;           Color color = (Color) obj;           return Objects.equals(this.color, color.color);       }          @Override       public int hashCode() {           return Objects.hash(color);       }   }      // Shape 接口   interface Shape {       void draw(Color color);   }      // Circle 类,实现 Shape 接口   class Circle implements Shape {       private String id; // 外部状态,如每个圆的唯一ID          public Circle(String id) {           this.id = id;       }          @Override       public void draw(Color color) {           System.out.println("Drawing Circle: " + id + " with color " + color.getColor());       }   }      // ShapeFactory 类,用于创建和管理 Shape 对象   class ShapeFactory {       private static final Map<String, Color> colorMap = new HashMap<>();          // 获取颜色对象,如果已存在则直接返回,否则创建新的并添加到map中       public static Color getColor(String color) {           Color result = colorMap.get(color);           if (result == null) {               result = new Color(color);               colorMap.put(color, result);           }           return result;       }          // 获取 Shape 对象(这里以 Circle 为例)       public static Shape getCircle(String id) {           return new Circle(id);       }   }      // 客户端代码   public class FlyweightPatternDemo {       public static void main(String[] args) {           Shape redCircle = ShapeFactory.getCircle("1");           Shape greenCircle = ShapeFactory.getCircle("2");              redCircle.draw(ShapeFactory.getColor("RED"));           greenCircle.draw(ShapeFactory.getColor("GREEN"));              // 由于颜色对象被共享,所以下面的两个 RED 颜色对象是相同的实例           Shape anotherRedCircle = ShapeFactory.getCircle("3");           anotherRedCircle.draw(ShapeFactory.getColor("RED"));       }   }

在这个例子中,Color类是内部状态,可以通过ShapeFactorygetColor方法被多个Shape对象共享。每个Shape对象(在这个例子中是Circle)都有自己的外部状态(如ID),这是不可共享的。ShapeFactory维护了一个colorMap来存储已经创建的颜色对象,以确保颜色的共享。

当运行此程序时,你会看到即使我们多次请求相同的颜色(如"RED"),我们也只会在内存中创建一个Color对象实例,并通过ShapeFactorygetColor方法返回该实例的引用。这减少了内存的使用,并提高了程序的效率。

七、结论

享元模式是一种有效的设计模式,用于在内存中有效地共享大量细粒度对象。它通过共享已存在的相似对象来减少内存使用,从而提高应用程序的性能和资源利用率。然而,使用享元模式也需要注意其缺点和适用场景,以确保系统设计的合理性和有效性。

如果享元模式对你有用,记得点赞收藏。

广告一刻

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