【设计模式】用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

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


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


相关文章
|
24天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
1月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
38 4
|
2月前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
53 0
[Java]23种设计模式
|
1月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
2月前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
2月前
|
设计模式 Java
Java设计模式
Java设计模式
34 0
|
2月前
|
设计模式 Java
Java设计模式之外观模式
这篇文章详细解释了Java设计模式之外观模式的原理及其应用场景,并通过具体代码示例展示了如何通过外观模式简化子系统的使用。
35 0
|
1天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
1天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
2天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
12 3