Flyweight(享元)

Flyweight(享元) 结构型 对象 1

Intent_意图2

运用共享技术有效地支持大量粒度的对象

Motivation_动机3

在有大量对象时,有可能会造成内存溢出,把其中共同的部分抽象出来,如果有相同的业务请求,直接返回内存中已有的对象

Applicability_适用性4

  1. 系统中有大量对内存消耗量大的、状态大部分可以外部化的对象
  2. 系统不依赖于这些对象身份,这些对象是不可分辨的
  3. 对象可以按照内蘊状态分为很多组,当把外蘊对象从对象中剔除时,每一组对象都可以用一个对象代替

Structure_结构5

在这里插入图片描述

Participants_参与者6

  • Flyweight(抽象享元) 所有的具体享元类的基类,为具体享元规范需要实现的公共接口
  • ConcreteFlyweight(具体享元) 实现抽象享元类所规范的接口
  • UnsharedConcreteFlyweight(非共享享元) 不可共享的外部状态
  • FlyweightFactory(享元工厂) 负责创建和管理享元角色

Collaborations_协作7

  1. Flyweight定义享元角色内部状态及外部状态的接口或实现
    ->intrinsic(内部状态):是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变。
    ->extrinsic(外部状态):外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态。
  2. ConcreteFlyweight实现Flyweight中定义的接口
    ->ConcreteFlyweight中的内部状态处理应与环境无关,不允许一个操作改变内部状态的同时,修改外部状态
  3. UnsharedConcreteFlyweight以参数形式注入到ConcreteFlyweight相关方法中
  4. FlyweightFactory创建管理Flyweight
    ->当客户请求一个享元对象时,FlyweightFactory检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在则创建一个新的享元对象
    ->通常情况下FlyweightFactory对象在整个系统中只有一个,使用单件

Comsequences_结果8

  • 优点
    大幅度减少对象的创建,降低系统的内存占用,提高效率
    将许多“虚拟”对象的状态集中管理
  • 缺点
    提高系统复杂度,需要分离外部和内部状态,且外部状态具有固有化性质,不应该随着内部状态的变化而变化
    一旦实现了享元模式,那么单个的逻辑实例将无法拥有独立而不同的行为
  • 用途
    系统有大量相似对象
    需要缓冲池的场景
    细粒度的对象具备较接近的外部状态,且内部状态与环境无关,也就是对象没有特定身份

Implementation/Sample Code_实现/范例代码910

Implementation

Flyweight

public abstract class Flyweight {
    // 内部状态
    private String intrinsic;
    // 外部状态
    protected final String Extrinsic;
 
    // 要求享元角色必须接受外部状态
    public Flyweight(String _Extrinsic) {
        this.Extrinsic = _Extrinsic;
    }
 
    // 定义业务操作
    public abstract void operate();
 
    // 内部状态的getter/setter
    public String getIntrinsic() {
        return intrinsic;
    }
 
    public void setIntrinsic(String intrinsic) {
        this.intrinsic = intrinsic;
    }
}

ConcreteFlyweight

public class ConcreteFlyweight extends Flyweight {
    // 接受外部状态
    public ConcreteFlyweight(String _Extrinsic) {
        super(_Extrinsic);
    }
 
    // 根据外部状态进行逻辑处理
    public void operate() {
        // TODO
    }
}

FlyweightFactory

public class FlyweightFactory {
    // 定义享元池
    private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
 
    // 享元工厂
    public static Flyweight getFlyweight(String extrinsic) {
        // 需要返回的对象
        Flyweight flyweight = null;
        // 在池中没有该对象
        if (pool.containsKey(extrinsic)) {
            flyweight = pool.get(extrinsic);
        } else {
            // 根据外部状态创建享元对象
            flyweight = new ConcreteFlyweight(extrinsic);
            // 放置到池中
            pool.put(Extrinsic, flyweight);
        }
        return flyweight;
    }
}

Sample Code

Flyweight

public interface Tree {
    void display();
    void plant(int xCoord, int yCoord);
}

ConcreteFlyweight

public class Redwood implements Tree {
    private int xCoord;
    private int yCoord;

	// xCoord, yCoord 共享
	@Override
    public void display() {
        System.out.println("Plant a redwood in x" + xCoord + ", y" + yCoord);
    }

	// xCoord, yCoord 不共享
    @Override
    public void plant(int xCoord, int yCoord) {
        this.xCoord = xCoord;
        this.yCoord = yCoord;
    }
}

FlyweightFactory

import java.util.HashMap;
import java.util.Random;

public class TreeFactory {
    private static final HashMap<String, Tree> treeArray = new HashMap<>();

    public Tree getRedwood() {
        Tree redwood = treeArray.get("redwood");
        if (redwood == null) {
            redwood = new Redwood();
            treeArray.put("redwood", redwood);
        }
        return redwood;
    }

    public static void displayTrees() {
        Random rand = new Random();
        for (Tree tree :
                treeArray.values()) {
            System.out.println(System.identityHashCode(tree));	// 打印对象地址
            tree.plant(rand.nextInt(100), rand.nextInt(100));	// 设置对象xCoord, yCoord
            tree.display();
        }
    }
}

Demo

public class Park {
    public static void main(String[] args) {
        TreeFactory treeFactory = new TreeFactory();
        treeFactory.getRedwood();	// 初始化享元对象
        treeFactory.displayTrees();
        treeFactory.getRedwood();	// 引用享元对象
        treeFactory.displayTrees();
    }
}

Result

1163157884
Plant a redwood in x31, y46
1163157884
Plant a redwood in x41, y64

Known Uses_已知应用11

Java中的String类,String对象是Final类型,对象一旦创建就不可改变,在JAVA中字符串常量都存在常量池中,JAVA会确保一个字符串常量在常量池中只有一个拷贝。String a = “abc”,其中"abc"就是一个字符串常量。
Demo

public class Test {
	public static void main(String[] args) {
		String a = "abc";
		String b = "abc";
		System.out.println(a == b);
	}
}

Result

true

Related Patterns_相关模式12

  • 单纯享元模式
    单纯享元模式中的所有的具体享元类都是可以共享的,不存在非共享的具体享元类
  • 复合享元模式
    复合享元模式中的有些享元对象是由一些单纯享元对象组合而成,它们就是复合享元对象。虽然复合享元对象本身不能共享,但它们可以分解成单纯享元对象再被共享
    复合享元类图:
    在这里插入图片描述

  1. 模式分类归属 ↩︎

  2. 意图:描述该模式的作用,以及该模式的定义 ↩︎

  3. 动机:给出了问题以及如何解决这个问题的具体场景 ↩︎

  4. 适用性:描述模式可以被应用在什么场合 ↩︎

  5. 结构:提供了图示,显示出参与此模式的类之间的关系 ↩︎

  6. 参与者:描述在此设计中所涉及到的类和对象在模式中的责任和角色 ↩︎

  7. 协作 :告诉参与者如何在此模式中合作 ↩︎

  8. 结果:描述采用此模式之后可能产生的效果,好的与不好的 ↩︎

  9. 实现:提供了在实现该模式时需要使用的技巧,以及应该小心面对的问题 ↩︎

  10. 范例代码:提供代码的片段 ↩︎

  11. 已知应用:用来描述已经在真实系统中发现的模式例子 ↩︎

  12. 相关模式:描述了此模式和其他模式之间的关系 ↩︎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值