【享元模式】

72 阅读3分钟

定义

享元模式(Flyweight Pattern)是一种结构型设计模式,它运用共享技术有效地支持大量细粒度的对象。享元模式的主要目的是减少系统中对象的数量,从而降低系统的内存占用和提高性能。

以下是享元模式的主要特点和定义:

一、主要角色

  1. Flyweight(抽象享元角色)

    • 定义了享元对象的接口,规定了享元对象必须实现的方法。
  2. ConcreteFlyweight(具体享元角色)

    • 实现了抽象享元角色所规定的接口,是可以共享的具体对象。
  3. FlyweightFactory(享元工厂角色)

    • 负责创建和管理享元对象,确保合理地共享享元对象。当客户端请求一个享元对象时,享元工厂会检查是否已经存在符合要求的享元对象,如果存在则直接返回,否则创建一个新的享元对象并返回给客户端。

业务

假设我们正在开发一个游戏,游戏中有很多不同种类的树,每种树有不同的外观,但相同种类的树可以共享一些属性。

一、定义抽象享元角色和具体享元角色

  1. 首先定义树的抽象享元接口Tree
public interface Tree {
    void draw(int x, int y);
}
  1. 然后实现具体享元角色,比如OakTree(橡树)和PineTree(松树):
public class OakTree implements Tree {
    private String texture; // 内部状态,假设是橡树的纹理图像路径

    public OakTree() {
        texture = "oak_texture.png";
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("Drawing Oak Tree at (" + x + ", " + y + ") with texture: " + texture);
    }
}

public class PineTree implements Tree {
    private String texture; // 内部状态,假设是松树的纹理图像路径

    public PineTree() {
        texture = "pine_texture.png";
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("Drawing Pine Tree at (" + x + ", " + y + ") with texture: " + texture);
    }
}

二、创建享元工厂

import java.util.HashMap;
import java.util.Map;

public class TreeFactory {
    private Map<String, Tree> trees = new HashMap<>();

    public Tree getTree(String type) {
        if (!trees.containsKey(type)) {
            switch (type) {
                case "oak":
                    trees.put(type, new OakTree());
                    break;
                case "pine":
                    trees.put(type, new PineTree());
                    break;
            }
        }
        return trees.get(type);
    }
}

三、使用享元模式

public class Main {
    public static void main(String[] args) {
        TreeFactory factory = new TreeFactory();

        Tree oakTree1 = factory.getTree("oak");
        oakTree1.draw(10, 20);

        Tree oakTree2 = factory.getTree("oak");
        oakTree2.draw(30, 40);

        Tree pineTree = factory.getTree("pine");
        pineTree.draw(50, 60);
    }
}

在这个例子中,Tree是抽象享元角色,OakTreePineTree是具体享元角色,TreeFactory是享元工厂。通过享元工厂,相同种类的树(如橡树和松树)可以被共享,减少了内存占用,提高了性能。外部状态(树的位置)在使用时传入具体享元对象的方法中。

总结

一、使用场景

  1. 系统中存在大量相似的对象,这些对象消耗大量的内存资源。例如在一个文本编辑软件中,不同位置的相同字符可以作为享元对象共享,只需要存储一份字符的图像数据,而不是为每个字符都创建一个独立的对象。
  2. 对象的大部分状态可以外部化,即可以将对象的状态分为内部状态和外部状态,内部状态可以共享,外部状态由客户端传入或者在使用时动态确定。

二、优点

  1. 减少内存占用:通过共享对象,减少了系统中对象的数量,从而降低了内存占用。
  2. 提高性能:由于减少了对象的创建和销毁,提高了系统的性能。

三、缺点

  1. 增加了系统的复杂性:需要将对象的状态分为内部状态和外部状态,并且需要实现享元工厂来管理享元对象,增加了系统的设计和实现难度。
  2. 可能会影响对象的独立性:享元对象的共享可能会导致对象之间的耦合度增加,影响对象的独立性。