设计模式-享元模式

设计模式-享元模式

享元模式的核心在于对象共享或者说是对象复用。

提到对象复用,你可能会想到单例模式这种局部唯一的复用,亦或者是线程池中线程的复用,或者连接池中连接的复用。那么它们和享元模式是一回事吗?

案例分析

实现一个文本功能,要求每个字符允许使用不同的字体或大小,因此每个字符都应该有 type 和 size 属性

java 复制代码
@Getter
public class Word {

    private Character word;

    // font 中存了该字符的 字体 和 大小属性
    private Font font;

    public Word(Character word, Font font) {
        this.word = word;
        this.font = font;
    }

}

如果最后要返回一串文本,类似下面的结果:

java 复制代码
        List<Word> wordList = List.of(
                new Word('A', Font.getFont("Arial", 12)),
                new Word('B', Font.getFont("Arial", 14)),
                new Word('C', Font.getFont("Arial", 16)),
                new Word('D', Font.getFont("Arial", 18)),
                new Word('E', Font.getFont("Arial", 12))
        );

其中字符 A 和字符 E 的格式其实是一样的,当然如果只有这 5 个对象,对内存的影响微乎其微,没有必要过度设计。但是一个文本文档可能有很多个字符,如果不进行设计完全有可能占用非常多的内存。

享元模式就是解决这个问题的

java 复制代码
public class Font {

    private String type;

    private int size;

    public Font(String type, int size) {
        this.type = type;
        this.size = size;
    }

    private static final List<Font> fontList = List.of(
            new Font("Arial", 12),
            new Font("Arial", 14),
            new Font("Arial", 16)
    );

    public static Font getFont(String type, int size) {
        for (Font font : fontList) {
            if (font.type.equals(type) && font.size == size) {
                return font;
            }
        }
        return new Font(type, size);
    }

}

Font 类中使用 fontList 缓存了常用的字体类型,在需要创建对象的时候优先从 fontList 中找,找不到再进行创建,这样多个字符可以引用同一个完全相同的对象,减少内存的占用。

java 复制代码
package com.xsdl.flyweight.txt;

import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<Word> wordList = List.of(
                new Word('A', Font.getFont("Arial", 12)),
                new Word('B', Font.getFont("Arial", 14)),
                new Word('C', Font.getFont("Arial", 16)),
                new Word('D', Font.getFont("Arial", 18)),
                new Word('E', Font.getFont("Arial", 12))
        );
        			                   System.out.println(wordList.get(0).getFont().equals(wordList.get(4).getFont()));
        System.out.println(wordList.get(0).getFont() == (wordList.get(4).getFont()));        
    }

}
拓展分析

其实享元模式在一些框架里还是经常使用的,例如 Integer 会默认缓存 -128 到 127 的对象,字符串常量池的设计,Redis 也会把 ok 等经常返回的指令进行缓存,不过注意这里的缓存其实是存储的意思,不是我们说的加快访问速度的缓存。

总结

所谓"享元",顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象,因为如果发生了变动会影响所有引用该对象的结构。

具体来讲,当一个系统中存在大量重复对象的时候,我们就可以利用享元模式,将对象设计成享元,在内存中只保留一份实例,供多处代码引用,这样可以减少内存中对象的数量,以起到节省内存的目的。当然也并非是完全相同的对象,当对象中重复的字段较多时,也可以抽取出常用的字段进行享元处理。

那享元与线程池等池化技术的复用的区别其实也显而易见了,享元模式主要是为了实现对象复用,节省内存;而池化技术中的复用则指的是重复使用,为了节省时间。

相关推荐
饼干哥哥6 小时前
用Claude Code跑通跨境电商的5大场景,顶10个人的团队
人工智能·设计模式·正则表达式
折哥的程序人生 · 物流技术专研7 小时前
第3篇:手写促销策略引擎(满减、打折、立减)
java·设计模式·策略模式·开闭原则·编程实战·扩充系列·促销引擎
折哥的程序人生 · 物流技术专研9 小时前
第3篇:手写一个饮品制作模板(附代码)
java·设计模式·行为型模式·模版方法模式·钩子方法·代码复用·编程实战
ttod_qzstudio10 小时前
【软考设计模式】单例模式:唯一实例的管控与线程安全精讲
单例模式·设计模式
折哥的程序人生 · 物流技术专研12 小时前
第4篇:模板方法 vs 策略模式,面试怎么选?
java·设计模式·策略模式·行为型模式·模版方法模式·扩充系列·继承v组合
小园子的小菜12 小时前
Java设计模式精讲:创建型+结构型模式(含生产级案例+相似模式对比)
学习·设计模式
geovindu1 天前
java:Abstract Factory Pattern
java·开发语言·后端·设计模式·抽象工厂模式·创建型模式
geovindu1 天前
java: Factory Method Pattern
java·开发语言·后端·设计模式·工厂方法模式·创建型模式
折哥的程序人生 · 物流技术专研1 天前
第2篇:模板方法模式核心:好莱坞原则
设计模式·uml·模板方法模式·行为型模式·钩子方法·扩充系列·好莱坞原则
折哥的程序人生 · 物流技术专研1 天前
第2篇:策略模式三大角色拆解与UML
java·设计模式·策略模式·uml·编程入门·行为型模式·扩充系列