Java设计模式-享元模式

createh54周前 (03-23)技术教程9

一、享元模式定义

享元模式是一种结构型设计模式,主要用于减少创建对象的数量,通过共享技术来有效支持大量细粒度对象的复用,避免大量相似对象的开销,从而减少内存占用并提高系统性能。

二、享元模式角色构成

  • 抽象享元(Flyweight):定义享元对象的接口,规定具体享元类需要实现的方法,通过这些方法可操作享元对象的内在状态以及接收外在状态参数。
  • 具体享元(ConcreteFlyweight):实现抽象享元类的接口,负责存储和管理享元对象的内在状态,实现相关业务逻辑方法,相同类型的具体享元对象可被多个地方共享使用。
  • 享元工厂(FlyweightFactory):负责创建和管理享元对象,维护一个享元对象的缓存池,当客户端请求时,先检查缓存池中是否存在该对象,存在则直接返回,否则创建新的享元对象放入缓存池后再返回给客户端。
  • 客户端(Client):负责使用享元对象,向享元工厂请求享元对象,并通过调用享元对象的方法来完成业务逻辑,调用时传入相应的外在状态参数,以区分不同情况下享元对象的具体行为。

三、享元模式适用场景

  • 游戏开发:如大型多人在线游戏中有大量的怪物、道具等对象。同类型的怪物具有相同的生命值、攻击力等属性,道具也有相同的属性和功能等,可将这些相同的属性作为内部状态共享,而怪物的位置、道具的持有玩家等作为外部状态,减少对象创建数量。
  • 图形绘制:在绘图软件中,绘制大量相同形状但位置不同的图形,如多个相同的圆形、矩形等。可将图形的形状、颜色等属性作为共享的内部状态,图形的坐标位置等作为外部状态。
  • 缓存系统:缓存中的数据很多时候具有相似性,比如缓存网页片段、数据库查询结果等。可以把相同的缓存内容作为共享的内部状态,而缓存的时间戳、缓存的来源等作为外部状态。

四、享元模式优缺点

  • 优点节省内存:对于大量重复出现且有相同部分属性的对象,只存储一份共有的内在状态,大大减少内存占用。提高性能:复用已有的享元对象,避免频繁创建对象的开销,提升程序整体性能,在处理大量对象时效果明显。便于维护:享元工厂集中管理享元对象,当需要对共享对象进行修改或扩展时,只需在享元工厂和具体享元类中进行操作,便于维护和管理。
  • 缺点增加复杂性:需要将对象的状态分为内部状态和外部状态,增加了程序设计和实现的复杂性,使程序逻辑更难理解。运行时间变长:读取享元模式的外部状态可能会使运行时间稍微变长,因为需要额外的操作来处理外部状态。线程安全问题:在多线程环境下,共享的享元对象可能会引起线程安全问题,需要进行适当的同步处理。

五、享元模式Java代码样例

// 抽象享元类,定义字符的基本操作接口
abstract class CharacterFlyweight {
    public abstract void display(char extrinsicState);
}

// 具体享元类,比如这里以英文字母为例
class ConcreteCharacterFlyweight extends CharacterFlyweight {
    private char intrinsicState; // 内在状态,这里假设是字符本身

    public ConcreteCharacterFlyweight(char c) {
        this.intrinsicState = c;
    }

    @Override
    public void display(char extrinsicState) {
        System.out.println("显示字符" + intrinsicState + ",外在状态(位置等):" + extrinsicState);
    }
}

// 享元工厂类,用于创建和管理享元对象
class CharacterFlyweightFactory {
    private Map flyweights = new HashMap<>();

    public CharacterFlyweight getCharacterFlyweight(char c) {
        if (flyweights.containsKey(c)) {
            return flyweights.get(c);
        } else {
            CharacterFlyweight newFlyweight = new ConcreteCharacterFlyweight(c);
            flyweights.put(c, newFlyweight);
            return newFlyweight;
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        CharacterFlyweightFactory factory = new CharacterFlyweightFactory();

        CharacterFlyweight charA = factory.getCharacterFlyweight('A');
        charA.display('1');

        CharacterFlyweight charB = factory.getCharacterFlyweight('B');
        charB.display('2');

        CharacterFlyweight charAAgain = factory.getCharacterFlyweight('A');
        charAAgain.display('3');
    }
}

在上述代码中,CharacterFlyweight是抽象享元类,
ConcreteCharacterFlyweight是具体享元类,CharacterFlyweightFactory是享元工厂类,Client是客户端。客户端通过享元工厂获取享元对象,并传入外部状态来调用享元对象的方法,实现了享元模式的基本功能。

相关文章

「Java」绘图入门和机制,绘图方法演示(绘制坦克)

目录1.绘图入门(绘制一个圆)1.第一步//1.先定义一个Mypanel,继承JPanel,画图行就在面板上画。//Mypanel可以理解为一个画板//Graphics可以理解为一个画笔,提供了很多绘...

stable-diffusion.java, Java调用Stable Diffusion实现AI 画图

今天了解了一个新的项目,stable-diffusion.java, 这是一个Java 项目,通过底层调用stable-diffusion.cpp, 从而让Java 项目也能AI 画图, 好神奇!st...

java Graphics2D 画图

在Java中,当需要画一些特殊的形状时,比如说椭圆、矩形等,可以使用 Graphics2D 来绘图。一些API:g.drawLine(3,3,50,50);//画一条线段 g.drawRect(80...

有趣的EXCEL&amp;vba作图

还记不记得之前有个日本老爷爷用EXCEL绘图,美轮美奂,可谓是心思巧妙。我是没有那样的艺术细胞,不过咱有自己的方式,用代码作图通过vba代码将指定的图片写入excel工作表中,可不是插入图片哦解题思...

游戏开发之旅-JavaScript绘制图形

本节是第四讲的第二十二小节,上一节课为大家介绍了Ajax技术,包括XmlHttpRequest对象和FetchAPI的基本用法,本节为大家继续介绍JavaScript绘制图形的方法(Canvas AP...

还能这么玩?用VsCode画类图、流程图、时序图、...不要太爽

软件设计中,有好几种图需要画,比如流程图、类图、组件图等,我知道大部分人画流程图一般都会用微软的viso绘制,我之前也是这个习惯。viso画图有个不好的地方是需要时刻去调整线条和边框已达到简洁美观,今...