【设计模式】用Java实现享元模式

简介: 享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来最小化内存使用和提高性能。享元模式通过将对象的状态分为内部状态(Intrinsic State)和外部状态(Extrinsic State),并共享内部状态,从而在大量相似对象之间实现有效的资源共享

一.享元模式介绍与使用场景


享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来最小化内存使用和提高性能。享元模式通过将对象的状态分为内部状态(Intrinsic State)和外部状态(Extrinsic State),并共享内部状态,从而在大量相似对象之间实现有效的资源共享。


内部状态是对象可共享的、独立于对象场景的状态,它可以被多个对象共享。外部状态是对象特定的、依赖于对象场景的状态,它不能被共享,每个对象都会保持一份独立的外部状态。


享元模式的关键思想是将对象的状态分离,并共享内部状态,而通过外部状态来区分和定制对象的行为。这样,在需要创建大量相似对象时,可以避免创建过多的对象,节省内存和系统资源。


应用场景:


1.当一个类需要创建大量相似的对象,且这些对象的区别仅在于它们的内部状态时。享元模式通过共享内部状态,减少了对象的数量,节省了内存和系统资源。

2.当对象的大部分状态可以被外部状态替代时,可以使用享元模式来共享内部状态,并将外部状态作为参数传递给享元对象。这样可以减少对象的数量,并且在使用时可以动态地改变外部状态,实现个性化的行为。

3.当需要频繁创建和销毁对象,且对象的创建和销毁操作消耗较大时,可以使用享元模式来重用已有对象,减少对象的创建和销毁次数,提高系统性能。

4.当系统中的多个对象共享相同的信息时,可以使用享元模式来将共享信息提取为共享对象,避免重复存储相同的数据,减少内存占用。


一些常见的应用场景包括:

文字处理器中的字符对象,可以使用享元模式来共享相同的字符对象,避免创建大量相同的字符对象。


图形界面中的图元对象,可以使用享元模式来共享相同的图元对象,提高图形渲染效率。


线程池中的线程对象,可以使用享元模式来共享线程对象,减少线程创建和销毁的开销。


缓存系统中的缓存对象,可以使用享元模式来共享相同的缓存对象,提高缓存命中率。

总之,享元模式适用于需要创建大量相似对象、可以共享内部状态、需要节省内存和系统资源的场景。它可以通过共享对象来提高系统性能,并且在一定程度上降低了对象的复杂性和内存消耗。


二.享元模式实现


下面是一个使用Java实现享元模式的简单示例:


首先,定义享元接口 Flyweight,它声明了一个操作方法 operate():

interface Flyweight {
    void operate(String extrinsicState);
}

然后,创建具体的享元类 ConcreteFlyweight,它实现了享元接口,并包含内部状态:

class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
    public void operate(String extrinsicState) {
        System.out.println("Intrinsic State: " + intrinsicState);
        System.out.println("Extrinsic State: " + extrinsicState);
        // 执行享元操作
    }
}

接下来,创建享元工厂类 FlyweightFactory,用于管理和共享享元对象:

import java.util.HashMap;
import java.util.Map;
class FlyweightFactory {
    private Map<String, Flyweight> flyweights;
    public FlyweightFactory() {
        flyweights = new HashMap<>();
    }
    public Flyweight getFlyweight(String intrinsicState) {
        if (flyweights.containsKey(intrinsicState)) {
            return flyweights.get(intrinsicState);
        } else {
            Flyweight flyweight = new ConcreteFlyweight(intrinsicState);
            flyweights.put(intrinsicState, flyweight);
            return flyweight;
        }
    }
}

最后,我们可以在客户端中使用享元工厂类来获取和使用享元对象:

public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        // 获取或创建享元对象
        Flyweight flyweight1 = factory.getFlyweight("SharedState");
        Flyweight flyweight2 = factory.getFlyweight("SharedState");
        // 使用享元对象
        flyweight1.operate("ExtrinsicState1");
        flyweight2.operate("ExtrinsicState2");
    }
}

输出结果为:

Intrinsic State: SharedState
Extrinsic State: ExtrinsicState1
Intrinsic State: SharedState
Extrinsic State: ExtrinsicState2

通过享元模式,我们可以共享具有相同内部状态的对象,避免创建过多的对象实例,从而节省内存和系统资源。在实际项目中,享元模式常用于需要创建大量相似对象的场景,例如线程池、缓存、文字处理器等。


需要注意的是,享元模式在共享对象时需要确保对象的内部状态是不可变的,以避免状态被修改造成共享对象的不一致性。


下面再举一个在实际项目中模拟一个文字处理器的字符对象共享的例子。


首先,定义享元接口 Character,它声明了一个方法 display():

interface Character {
    void display();
}

然后,创建具体的享元类 ConcreteCharacter,它实现了享元接口,并包含内部状态:

class ConcreteCharacter implements Character {
    private char symbol;
    public ConcreteCharacter(char symbol) {
        this.symbol = symbol;
    }
    public void display() {
        System.out.println("Character: " + symbol);
    }
}

接下来,创建享元工厂类 CharacterFactory,用于管理和共享字符对象:

import java.util.HashMap;
import java.util.Map;
class CharacterFactory {
    private Map<Character, Character> characters;
    public CharacterFactory() {
        characters = new HashMap<>();
    }
    public Character getCharacter(char symbol) {
        if (characters.containsKey(symbol)) {
            return characters.get(symbol);
        } else {
            Character character = new ConcreteCharacter(symbol);
            characters.put(symbol, character);
            return character;
        }
    }
}

最后,我们可以在客户端中使用享元工厂类来获取和使用字符对象:

public class Client {
    public static void main(String[] args) {
        CharacterFactory factory = new CharacterFactory();
        // 获取或创建字符对象
        Character character1 = factory.getCharacter('A');
        Character character2 = factory.getCharacter('B');
        Character character3 = factory.getCharacter('A');
        // 使用字符对象
        character1.display(); // 输出:Character: A
        character2.display(); // 输出:Character: B
        character3.display(); // 输出:Character: A
        System.out.println(character1 == character3); // 输出:true,字符对象被共享
    }
}

输出结果为:

Character: A
Character: B
Character: A
true

通过享元模式,我们可以共享具有相同内部状态的字符对象,避免创建多个相同的字符对象,节省了内存和系统资源。在实际项目中,享元模式可以应用于文字处理器、图形渲染器等需要大量相似对象的场景,从而提高系统性能和资源利用率。


需要注意的是,在享元模式中,内部状态应该是不可变的,以确保共享对象的一致性。如果需要修改内部状态,应该通过外部状态来实现个性化的行为。


相关文章
|
6天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
2天前
|
设计模式 Java
Java设计模式:组合模式的介绍及代码演示
组合模式是一种结构型设计模式,用于将多个对象组织成树形结构,并统一处理所有对象。例如,统计公司总人数时,可先统计各部门人数再求和。该模式包括一个通用接口、表示节点的类及其实现类。通过树形结构和节点的通用方法,组合模式使程序更易扩展和维护。
Java设计模式:组合模式的介绍及代码演示
|
6天前
|
设计模式 安全 算法
【Java面试题汇总】设计模式篇(2023版)
谈谈你对设计模式的理解、七大原则、单例模式、工厂模式、代理模式、模板模式、观察者模式、JDK中用到的设计模式、Spring中用到的设计模式
【Java面试题汇总】设计模式篇(2023版)
|
6天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式
|
21天前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
37 2
|
21天前
|
设计模式 Java
Java 设计模式之谜:工厂模式与抽象工厂模式究竟隐藏着怎样的神奇力量?
【8月更文挑战第30天】在Java编程中,设计模式为常见问题提供了高效解决方案。工厂模式与抽象工厂模式是常用的对象创建型设计模式,能显著提升代码的灵活性、可维护性和可扩展性。工厂模式通过定义创建对象的接口让子类决定实例化哪个类;而抽象工厂模式则进一步提供了一个创建一系列相关或相互依赖对象的接口,无需指定具体类。这种方式使得系统更易于扩展和维护。
30 1
|
21天前
|
设计模式 Java
重构你的代码:探索Java中的混合、装饰器与组合设计模式
【8月更文挑战第30天】在软件开发中,设计模式为特定问题提供了结构化的解决方案,使代码更易理解、维护及扩展。本文将介绍三种常用的 Java 设计模式:混合模式、装饰器模式与组合模式,并附有示例代码展示实际应用。混合模式允许通过继承多个接口或抽象类实现多重继承;装饰器模式可在不改变对象结构的情况下动态添加新功能;组合模式则通过树形结构表示部分-整体层次,确保客户端处理单个对象与组合对象时具有一致性。
15 1
|
3月前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
42 4
|
1月前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
|
4月前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式