设计模式之享元模式

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。

享元与不可变性

由于享元对象可在不同的情景中使用, 你必须确保其状态不能被修改。 享元类的状态只能由构造函数的参数进行一次性初始化, 它不能对其他对象公开其设置器或公有成员变量。

享元工厂

为了能更方便地访问各种享元, 你可以创建一个工厂方法来管理已有享元对象的缓存池。 工厂方法从客户端处接收目标享元对象的内在状态作为参数, 如果它能在缓存池中找到所需享元, 则将其返回给客户端; 如果没有找到, 它就会新建一个享元, 并将其添加到缓存池中。

你可以选择在程序的不同地方放入该函数。 最简单的选择就是将其放置在享元容器中。 除此之外, 你还可以新建一个工厂类, 或者创建一个静态的工厂方法并将其放入实际的享元类中。

享元模式适合应用场景

仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式。

应用该模式所获的收益大小取决于使用它的方式和情景。 它在下列情况中最有效:

程序需要生成数量巨大的相似对象

这将耗尽目标设备的所有内存

对象中包含可抽取且能在多个对象间共享的重复状态。

实现方式

将需要改写为享元的类成员变量拆分为两个部分:

内在状态: 包含不变的、 可在许多对象中重复使用的数据的成员变量。

外在状态: 包含每个对象各自不同的情景数据的成员变量

保留类中表示内在状态的成员变量, 并将其属性设置为不可修改。 这些变量仅可在构造函数中获得初始数值。

找到所有使用外在状态成员变量的方法, 为在方法中所用的每个成员变量新建一个参数, 并使用该参数代替成员变量。

你可以有选择地创建工厂类来管理享元缓存池, 它负责在新建享元时检查已有的享元。 如果选择使用工厂, 客户端就只能通过工厂来请求享元, 它们需要将享元的内在状态作为参数传递给工厂。

客户端必须存储和计算外在状态 (情景) 的数值, 因为只有这样才能调用享元对象的方法。 为了使用方便, 外在状态和引用享元的成员变量可以移动到单独的情景类中。

与其他模式的关系

你可以使用享元模式实现组合模式树的共享叶节点以节省内存。

享元展示了如何生成大量的小型对象, 外观模式则展示了如何用一个对象来代表整个子系统。

如果你能将对象的所有共享状态简化为一个享元对象, 那么享元就和单例模式类似了。 但这两个模式有两个根本性的不同。

只会有一个单例实体, 但是_享元_类可以有多个实体, 各实体的内在状态也可以不同。

_单例_对象可以是可变的。 享元对象是不可变的。

Java示例代码:

import java.util.*;

public class FlyWeightPattern {

    public static void main(String[] args) {

        ShapeFactory factory = new ShapeFactory();

        Random random = new Random();

        String[] colors = {"red", "blue", "green", "white", "black"};

        for (int i = 1; i <= 100; i ++ ) {

            int x = random.nextInt(colors.length); // \[0 ~ 4\]

            Shape shape = factory.getShape(colors[x]);

            System.out.print("第" + i + "个圆:");

            shape.draw(random.nextInt(2022), random.nextInt(528));

        }

    }

}

class ShapeFactory {

    private Map<String, Shape> map = new HashMap<String, Shape>();

    public Shape getShape(String key) {

        if (!map.containsKey(key)) {

            map.put(key, new Circle(key));

            System.out.println("create color:" + key + " circle");

        }

        return map.get(key);

    }

}

abstract class Shape {

    protected String color;

    public abstract void draw(int x, int y);

}

class Circle extends Shape {

    public Circle(String color) {

        this.color = color;

    }

    @Override

    public void draw(int x, int y) {

        System.out.println("draw a color:" + color + " circle x:" + x + " y:" + y);

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysh05

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值