1. 基础概念

享元模式是一种结构型设计模式,在享元模式中,对象被设计为可共享的,可以被多个上下文使用,而不必在每个上下文中都创建新的对象。

想要了解享元模式,就必须要区分什么是内部状态,什么是外部状态。

  • 内部状态是指那些可以被多个对象共享的状态,它存储在享元对象内部,并且对于所有享元对象都是相同的,这部分状态通常是不变的。
  • 而外部状态是享元对象依赖的、可能变化的部分。这部分状态不存储在享元对象内部,而是在使用享元对象时通过参数传递给对象。

举个例子,图书馆中有很多相同的书籍,但每本书都可以被多个人借阅,图书馆里的书就是内部状态,人就是外部状态。

再举个开发中的例子,假设我们在构建一个简单的图形编辑器,用户可以在画布上绘制不同类型的图形,而图形就是所有图形对象的内部状态(不变的),而图形的坐标位置就是图形对象的外部状态(变化的)。

如果图形编辑器中有成千上万的图形对象,每个图形对象都独立创建并存储其内部状态,那么系统的内存占用可能会很大,在这种情况下,享元模式共享相同类型的图形对象,每种类型的图形对象只需创建一个共享实例,然后通过设置不同的坐标位置个性化每个对象,通过共享相同的内部状态,降低了对象的创建和内存占用成本。

2. 基本结构

享元模式包括以下几个重要角色:

image-20240514234743751

  • 享元接口Flyweight: 所有具体享元类的共享接口,通常包含对外部状态的操作。
  • 具体享元类ConcreteFlyweight: 继承Flyweight类或实现享元接口,包含内部状态。
  • 享元工厂类FlyweightFactory: 创建并管理享元对象,当用户请求时,提供已创建的实例或者创建一个。
  • 客户端Client: 维护外部状态,在使用享元对象时,将外部状态传递给享元对象。

3. 简易实现

享元模式的实现通常涉及以下步骤:

  1. 定义享元接口,接受外部状态作为参数并进行处理。
1
2
3
4
5
// 步骤 1: 定义享元接口
interface Flyweight {
// 操作外部状态
void operation(String externalState);
}
  1. 实现具体享元类, 存储内部状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
// 步骤 2: 实现具体享元类
class ConcreteFlyweight implements Flyweight {
private String intrinsicState; // 内部状态

public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}

@Override
public void operation(String externalState) {
System.out.println("Intrinsic State: " + intrinsicState + ", External State: " + externalState);
}
}
  1. 创建享元工厂类,创建并管理Flyweight对象,当用户请求一个Flyweight时,享元工厂会提供一个已经创建的实例或者创建一个。
1
2
3
4
5
6
7
8
9
10
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);
}
}
  1. 客户端使用享元模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();

// 获取或创建享元对象,并传递外部状态
Flyweight flyweight1 = factory.getFlyweight("A");
flyweight1.operation("External State 1");

Flyweight flyweight2 = factory.getFlyweight("B");
flyweight2.operation("External State 2");

Flyweight flyweight3 = factory.getFlyweight("A"); // 重复使用已存在的享元对象
flyweight3.operation("External State 3");
}
}

4. 使用场景

使用享元模式的关键在于包含大量相似对象,并且这些对象的内部状态可以共享。具体的应用场景包括文本编辑器,图形编辑器,游戏中的角色创建,这些对象的内部状态比较固定(外观,技能,形状),但是外部状态变化比较大时,可以使用。


本站由 卡卡龙 使用 Stellar 1.27.0 主题创建

本站访问量 次. 本文阅读量 次.