设计模式- 享元模式(Flyweight Pattern)结构|原理|优缺点|场景|示例

                                     设计模式(分类)        设计模式(六大原则)   

    创建型(5种)        工厂方法         抽象工厂模式        单例模式        建造者模式        原型模式

    结构型(7种)        适配器模式        装饰器模式        代理模式        ​​​​​​外观模式      桥接模式        组合模式       享元模式

    行为型(11种)      策略模式        模板方法模式        观察者模式        迭代器模式     责任链模式     命令模式    备忘录模式          状态模式         访问者模式        中介者模式 


享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享已存在的类似对象来有效支持大量细粒度对象的复用,从而降低系统内存占用并提高性能。它适用于对象的大部分状态都可以被外部化,而只有少量内在状态(共享部分)需要存储在享元对象中。这种模式通过共享内部状态相同的对象,避免了大量相似对象的创建。

模式结构

享元模式主要包含以下角色:

  1. Flyweight(抽象享元类)

    • 定义了享元对象的公共接口,通常包括共享状态的访问方法和非共享状态的操作方法。
    • 提供一个或多个工厂方法,用于创建或获取享元对象。
  2. ConcreteFlyweight(具体享元类)

    • 实现抽象享元类的接口,存储享元对象的内部状态(共享部分)。
    • 提供操作内部状态的方法。
  3. UnsharedConcreteFlyweight(非共享具体享元类,可选)

    • 对于某些不适合共享的状态,可以创建非共享的具体享元类来处理。
  4. FlyweightFactory(享元工厂)

    • 负责创建和管理享元对象,确保享元对象的唯一性。
    • 提供一个方法来获取享元对象,如果该对象已存在,则直接返回已创建的享元对象;否则创建一个新的享元对象并返回。
  5. Client(客户端)

    • 通过享元工厂请求享元对象。
    • 向享元对象传递外部状态(非共享部分)。

工作原理

  • 客户端:通过享元工厂请求享元对象,并向对象传递必要的外部状态。
  • FlyweightFactory:根据客户端请求创建或查找已存在的享元对象,并返回给客户端。
  • ConcreteFlyweight:存储并操作内部状态,对外部状态作出响应。

优缺点

优点
  • 减少对象创建数量:通过共享内部状态相同的对象,显著减少了系统中对象的数量,节省内存。
  • 提高性能:由于对象数量减少,对象的创建、销毁和垃圾回收等操作的开销也相应减小。
  • 支持大量细粒度对象:对于需要创建大量相似对象的场景,享元模式能有效应对。
缺点
  • 增加复杂性:引入享元模式后,系统需要管理享元对象的创建、共享和外部状态传递,增加了设计和实现的复杂性。
  • 外部状态管理:客户端需要负责传递外部状态给享元对象,这可能使得客户端代码与享元对象的交互变得复杂。
  • 不适合所有场景:并非所有对象都能被共享。只有当对象的大部分状态可以被外部化时,享元模式才适用。

适用场景

  • 对象数量巨大且内部状态大部分相同:当系统需要处理大量相似对象,且这些对象的大部分状态是共享的,可以考虑使用享元模式。
  • 内存消耗成为瓶颈:当内存资源有限,对象创建和存储的成本较高时,通过享元模式减少对象数量可以改善性能。
  • 对象的创建成本高于使用成本:如果创建一个对象比多次复用该对象更耗时或耗资源,享元模式可以减少创建开销。

代码示例(以Java为例)

// 抽象享元类
interface Character {
    void display(char symbol, int x, int y);
}

// 具体享元类
class CharacterImpl implements Character {
    private char symbol;

    public CharacterImpl(char symbol) {
        this.symbol = symbol;
    }

    @Override
    public void display(char symbol, int x, int y) {
        System.out.println("Displaying character '" + symbol + "' at (" + x + ", " + y + ")");
        // 这里假设实际操作是绘制字符到屏幕上,但实际位置由外部状态(x, y)决定
    }
}

// 享元工厂
class CharacterFactory {
    private Map<Character, CharacterImpl> flyweights = new HashMap<>();

    public Character getCharacter(char symbol) {
        if (!flyweights.containsKey(symbol)) {
            flyweights.put(symbol, new CharacterImpl(symbol));
        }
        return flyweights.get(symbol);
    }
}

// 客户端代码
public class FlyweightPatternDemo {
    public static void main(String[] args) {
        CharacterFactory factory = new CharacterFactory();

        Character a = factory.getCharacter('A');
        Character b = factory.getCharacter('B');

        a.display('A', 10, 10);
        b.display('B', 20, 20);

        // 即使多次请求相同的字符,也不会创建新的对象
        Character anotherA = factory.getCharacter('A');
        assert a == anotherA;  // 指向同一享元对象
    }
}

代码示例(以Python为例)

使用Python实现享元模式的一个示例,我们将创建一个简单的字符渲染系统,其中每个字符都是一个享元对象,它们的内部状态是字符本身,而外部状态则是渲染时的位置(x, y坐标):

from typing import Dict, Tuple
import weakref


class Character:
    """抽象享元类"""

    def __init__(self, symbol: str):
        self._symbol = symbol

    def display(self, position: Tuple[int, int]):
        """显示字符,外部状态由客户端传递"""
        print(f"Displaying character '{self._symbol}' at {position}")


class CharacterFactory:
    """享元工厂类"""

    _flyweights: Dict[str, weakref.ReferenceType[Character]] = {}

    @classmethod
    def get_character(cls, symbol: str) -> Character:
        """
        获取或创建字符享元对象。

        如果字符享元已经存在,则直接返回;否则创建新的享元对象并添加到缓存中。
        """
        flyweight_ref = cls._flyweights.get(symbol)
        if flyweight_ref is not None and flyweight_ref() is not None:
            return flyweight_ref()

        flyweight = Character(symbol)
        cls._flyweights[symbol] = weakref.ref(flyweight)
        return flyweight


def main():
    factory = CharacterFactory()

    # 请求并显示两个不同的字符
    a = factory.get_character('A')
    a.display((10, 10))

    b = factory.get_character('B')
    b.display((20, 20))

    # 再次请求相同的字符,应当返回已存在的享元对象
    another_a = factory.get_character('A')
    assert a is another_a

    print("Characters displayed using the Flyweight pattern.")


if __name__ == "__main__":
    main()

在这个Python示例中:

  • Character类作为抽象享元类,定义了享元对象的公共接口(display方法),并存储了字符的内部状态(字符符号)。
  • CharacterFactory类作为享元工厂,使用一个字典来缓存已创建的享元对象。字典的键是字符符号,值是弱引用(weakref)以避免循环引用导致内存泄漏。当客户端请求某个字符时,如果该字符的享元对象已存在,则直接返回;否则创建一个新的享元对象,添加到字典中,并返回该对象的弱引用。
  • main函数展示了客户端如何使用享元工厂来获取字符享元对象,并通过display方法传递外部状态(显示位置)。当请求相同的字符时,工厂会返回同一个享元对象,证明了享元模式的有效性。

运行此代码,将会看到字符在指定位置被正确显示,且两次请求相同的字符时,返回的是同一个对象实例。这就是享元模式在Python中的应用。

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,享元模式是一种结构设计模式,它的主要目的是通过共享尽可能多的对象来减少内存使用和对象创建的数量,从而提高应用程序的性能和效率。在享元模式中,共享的对象被称为“享元”,而不共享的对象被称为“非享元”。 以下是一个简单的Java代码示例,展示了如何实现享元模式: ```java import java.util.HashMap; import java.util.Map; public class FlyweightFactory { private static final Map<String, Flyweight> flyweights = new HashMap<>(); public static Flyweight getFlyweight(String key) { Flyweight flyweight = flyweights.get(key); if (flyweight == null) { flyweight = new ConcreteFlyweight(); flyweights.put(key, flyweight); } return flyweight; } } public interface Flyweight { void operation(); } public class ConcreteFlyweight implements Flyweight { @Override public void operation() { System.out.println("ConcreteFlyweight operation"); } } public class Client { public static void main(String[] args) { Flyweight flyweight1 = FlyweightFactory.getFlyweight("key1"); Flyweight flyweight2 = FlyweightFactory.getFlyweight("key1"); flyweight1.operation(); flyweight2.operation(); System.out.println(flyweight1 == flyweight2); // true } } ``` 在这个示例中,FlyweightFactory类是享元工厂,它负责维护享元对象的缓存池,并通过getFlyweight()方法来获取享元对象。Flyweight接口是享元对象的基本接口,它定义了享元对象的操作方法。ConcreteFlyweight类是具体的享元类,它实现了Flyweight接口以提供具体的实现。 享元模式的优点: 1. 大大减少内存使用和对象创建的数量,提高应用程序的性能和效率。 2. 重复利用已存在的对象,减少了重复创建对象的开销。 3. 分离内部状态和外部状态,使得共享对象能够在不同的环境下被重复使用。 享元模式的缺点: 1. 由于共享对象的状态是不可变的,因此不能满足所有的业务需求。 2. 享元模式需要对享元对象进行管理,增加了系统的复杂性。 享元模式的应用场景: 1. 对象数量巨大,且需要频繁创建和销毁的场景。 2. 对象具有一定的内部状态和外部状态,且内部状态相对稳定,外部状态易变的场景。 3. 系统需要大量的相似对象,而且这些对象需要共享一些公共信息的场景

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值