享元模式

什么是享元模式

享元模式(Flyweight Pattern)是一种对象结构型设计模式,用于减少创建对象的数量,以减少内存占用和提高系统性能。它通过共享已经存在的对象来避免创建大量相似的对象,从而降低内存消耗。

在享元模式中,通常会有一些细粒度的对象,它们具有一些共同的属性,但是某些属性可能会变化。

  • 优点
    • 减少对象数量:通过共享对象,可以显著减少系统中对象的数量,从而节省内存空间。
    • 提高性能:由于减少了对象的创建和销毁,可以提高系统的性能。
  • 缺点
    • 增加系统复杂性:引入享元模式可能会增加系统的复杂性,特别是当处理内在状态和外在状态的分离时。
    • 可能不适用于所有场景:不是所有情况都适合使用享元模式,例如当对象的状态变化非常频繁时,共享对象可能不是最佳选择。

核心

  • 享元模式以共享的方式高效的支持大量细粒度对象的复用。
  • 享元对象能做到共享的关键是区分了内部状态和外部状态。
    • 内部状态:可以共享,不会岁环境变化发生改变
    • 外部状态:不可以共享,会随环境变化二改变

享元模式的实现

  • 抽象享元类(Flyweight):通常是一个接口或者抽象类,声明公共的方法,这些方法可以想外界提供对象的内部状态及设置外部状态
  • 具体享元类(ConcreteFlyweight):为内部状态提供成员变量进行存储
  • 非共享享元类(UnsharedConcreteFlyweight):不能为共享的子类可以设计成非共享享元类
  • 享元工厂(FlyweightFactory):创建并管理享元对象享元池一般设计成键值对

案例

对于围棋,棋子进行简单可以划分:
内部状态:颜色
外部状态:棋盘坐标

UML

03-JAVA设计模式-享元模式-LMLPHP

实现步骤:

  1. 定义外部状态:地址Address

  2. 定义享元接口:提供操作外部状态的接口,通过传入地址获取外部状态地址的信息

  3. 定义享元接口的实现(围棋)

    • 通过属性设置内部状态,并提供内部状态的设置及调用方法(这里只提供了设置方法)
    • 通过实现享元接口,传入外部状态调用外部状态方法或获取外部状态属性
  4. 享元工厂

    • 定义享元池(通常以键值对形式缓存),用于缓存共享内部状态(该方法只适用单线程,多线程需要进行优化)
    • 提供获取内部状态的方法,如果享元池中已存在,则享元池中对象,否则新建一个对象并设置到享元池中

代码实现

Address.java

// 定义外部状态
public class Address {
    private int x;
    private int y;

    public Address(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Flyweight.java

// 享元接口:
// *  提供操作外部状态的接口
public interface Flyweight {
    // 获取棋子信息:
//     *  通过传入地址获取外部状态地址的信息
    void getInfo(Address address);
}

ChessPieces.java

//定义享元接口的实现:
// 围棋:
//  通过属性设置内部状态,并提供内部状态的设置及调用方法(这里只提供了设置方法)、
//  通过实现享元接口,传入外部状态调用外部状态方法或获取外部状态属性
public class ChessPieces implements Flyweight{
    private String color;

    public ChessPieces(String color) {
        this.color = color;
    }

    @Override
    public void getInfo(Address address) {
        System.out.printf("颜色:%s,坐标:x=%s,y=%s%n",color,address.getX(),address.getY());
    }
}

FlyweightFactory.java

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

// 享元工厂
// * 定义享元池(通常以键值对形式缓存),用于缓存共享内部状态(该方法只适用单线程,多线程需要进行优化)
// * 提供获取内部状态的方法,如果享元池中已存在,则享元池中对象,否则新建一个对象并设置到享元池中
public class FlyweightFactory {

    // 定义享元池
    private Map<String, Flyweight> mapPool = new HashMap<String, Flyweight>();

    // 提供获取内部状态的方法
    public Flyweight getChessPieces(String key){
        Flyweight flyweight = mapPool.get(key);
        if(flyweight == null){
            flyweight = new ChessPieces(key);
            mapPool.put(key, flyweight);
        }
        return flyweight;
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        FlyweightFactory flyweightFactory = new FlyweightFactory();
        Flyweight chessPieces = flyweightFactory.getChessPieces("白色");
        chessPieces.getInfo(new Address(1,2));
    }
}

执行结果:

03-JAVA设计模式-享元模式-LMLPHP

gitee源码

04-12 06:58