当前位置: 首页 > article >正文

【设计模式】【结构型模式(Structural Patterns)】之享元模式(Flyweight Pattern)

1. 设计模式原理说明

享元模式(Flyweight Pattern) 是一种用于性能优化的设计模式,其主要目的是通过共享尽可能多的对象来有效地支持大量的细粒度的对象。在享元模式中,细粒度的对象被称为“享元”,这些对象可以被共享,以减少内存的使用并提高效率。享元模式特别适用于那些对象数量巨大且大部分状态可以外部化的情况。

主要角色
  1. Flyweight(享元):定义一个接口,通过这个接口,Flyweight 可以接受并作用于外部状态。
  2. ConcreteFlyweight(具体享元):实现 Flyweight 接口,并为内部状态增加存储空间。一个 ConcreteFlyweight 对象必须是可共享的。通常情况下,它会被多个对象所共享。
  3. UnsharedConcreteFlyweight(不可共享的具体享元):并不是所有的 Flyweight 子类都需要被共享,因此 Flyweight 接口中声明的方法对于不可共享的具体享元同样适用。
  4. FlyweightFactory(享元工厂):负责创建和管理 Flyweight 对象。确保合理地共享 Flyweight 对象,当用户请求一个 Flyweight 对象时,FlyweightFactory 提供一个已有的实例或者创建一个新的实例。

2. UML 类图及解释

UML 类图
+-------------------+                +-----------------------+
|   Flyweight       |<--(implements)| ConcreteFlyweight     |
|-------------------|                |-----------------------|
| + operation(extrinsicState: String): void | + operation(extrinsicState: String): void |
+-------------------+                +-----------------------+
                                       ^
                                       |
+-----------------------+              |
| UnsharedConcreteFlyweight |          |
|-----------------------|             |
| + operation(extrinsicState: String): void | +-----------------------+
+-----------------------+                | FlyweightFactory         |
                                           +-----------------------+
                                           | + getFlyweight(key: String): Flyweight |
                                           +-----------------------+
类图解释
  • Flyweight:定义了一个接口,通过这个接口,享元可以接收并作用于外部状态。
  • ConcreteFlyweight:实现了 Flyweight 接口,包含内部状态,可以被多个对象共享。
  • UnsharedConcreteFlyweight:虽然实现了 Flyweight 接口,但它的对象不能被共享,每个实例都有自己的状态。
  • FlyweightFactory:负责创建和管理享元对象。它使用一个数据结构(如哈希表)来存储已经创建的享元对象,以便复用。

3. 代码案例及逻辑详解

Java 代码案例
// 享元接口
interface Flyweight {
    void operation(String extrinsicState);
}

// 具体享元
class ConcreteFlyweight implements Flyweight {
    private final String intrinsicState;

    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }

    @Override
    public void operation(String extrinsicState) {
        System.out.println("Intrinsic State = " + this.intrinsicState);
        System.out.println("Extrinsic State = " + extrinsicState);
    }
}

// 不可共享的具体享元
class UnsharedConcreteFlyweight implements Flyweight {
    @Override
    public void operation(String extrinsicState) {
        System.out.println("I am not shared.");
    }
}

// 享元工厂
class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fly1 = factory.getFlyweight("Key1");
        fly1.operation("Extrinsic State 1");

        Flyweight fly2 = factory.getFlyweight("Key1");
        fly2.operation("Extrinsic State 2");

        Flyweight unshared = new UnsharedConcreteFlyweight();
        unshared.operation("Extrinsic State 3");
    }
}
C++ 代码案例
#include <iostream>
#include <map>
#include <memory>
#include <string>

// 享元接口
class Flyweight {
public:
    virtual void operation(const std::string& extrinsicState) const = 0;
    virtual ~Flyweight() {}
};

// 具体享元
class ConcreteFlyweight : public Flyweight {
private:
    std::string intrinsicState;
public:
    ConcreteFlyweight(const std::string& state) : intrinsicState(state) {}
    void operation(const std::string& extrinsicState) const override {
        std::cout << "Intrinsic State = " << intrinsicState << std::endl;
        std::cout << "Extrinsic State = " << extrinsicState << std::endl;
    }
};

// 不可共享的具体享元
class UnsharedConcreteFlyweight : public Flyweight {
public:
    void operation(const std::string& extrinsicState) const override {
        std::cout << "I am not shared." << std::endl;
    }
};

// 享元工厂
class FlyweightFactory {
private:
    std::map<std::string, std::shared_ptr<Flyweight>> flyweights;
public:
    std::shared_ptr<Flyweight> getFlyweight(const std::string& key) {
        if (flyweights.find(key) == flyweights.end()) {
            flyweights[key] = std::make_shared<ConcreteFlyweight>(key);
        }
        return flyweights[key];
    }
};

// 客户端
int main() {
    FlyweightFactory factory;
    auto fly1 = factory.getFlyweight("Key1");
    fly1->operation("Extrinsic State 1");

    auto fly2 = factory.getFlyweight("Key1");
    fly2->operation("Extrinsic State 2");

    UnsharedConcreteFlyweight unshared;
    unshared.operation("Extrinsic State 3");

    return 0;
}
Python 代码案例
from abc import ABC, abstractmethod
from collections import defaultdict

# 享元接口
class Flyweight(ABC):
    @abstractmethod
    def operation(self, extrinsic_state: str) -> None:
        pass

# 具体享元
class ConcreteFlyweight(Flyweight):
    def __init__(self, intrinsic_state: str) -> None:
        self._intrinsic_state = intrinsic_state

    def operation(self, extrinsic_state: str) -> None:
        print(f"Intrinsic State = {self._intrinsic_state}")
        print(f"Extrinsic State = {extrinsic_state}")

# 不可共享的具体享元
class UnsharedConcreteFlyweight(Flyweight):
    def operation(self, extrinsic_state: str) -> None:
        print("I am not shared.")

# 享元工厂
class FlyweightFactory:
    _flyweights: dict[str, Flyweight] = {}

    def get_flyweight(self, key: str) -> Flyweight:
        if key not in self._flyweights:
            self._flyweights[key] = ConcreteFlyweight(key)
        return self._flyweights[key]

# 客户端
if __name__ == "__main__":
    factory = FlyweightFactory()
    fly1 = factory.get_flyweight("Key1")
    fly1.operation("Extrinsic State 1")

    fly2 = factory.get_flyweight("Key1")
    fly2.operation("Extrinsic State 2")

    unshared = UnsharedConcreteFlyweight()
    unshared.operation("Extrinsic State 3")
Go 代码案例
package main

import (
	"fmt"
)

// 享元接口
type Flyweight interface {
	operation(extrinsicState string)
}

// 具体享元
type ConcreteFlyweight struct {
	intrinsicState string
}

func (f *ConcreteFlyweight) operation(extrinsicState string) {
	fmt.Printf("Intrinsic State = %s\n", f.intrinsicState)
	fmt.Printf("Extrinsic State = %s\n", extrinsicState)
}

// 不可共享的具体享元
type UnsharedConcreteFlyweight struct{}

func (u *UnsharedConcreteFlyweight) operation(extrinsicState string) {
	fmt.Println("I am not shared.")
}

// 享元工厂
type FlyweightFactory struct {
	flyweights map[string]Flyweight
}

func NewFlyweightFactory() *FlyweightFactory {
	return &FlyweightFactory{flyweights: make(map[string]Flyweight)}
}

func (f *FlyweightFactory) getFlyweight(key string) Flyweight {
	if fw, ok := f.flyweights[key]; ok {
		return fw
	}
	fw := &ConcreteFlyweight{intrinsicState: key}
	f.flyweights[key] = fw
	return fw
}

// 客户端
func main() {
	factory := NewFlyweightFactory()
	fly1 := factory.getFlyweight("Key1")
	fly1.operation("Extrinsic State 1")

	fly2 := factory.getFlyweight("Key1")
	fly2.operation("Extrinsic State 2")

	unshared := &UnsharedConcreteFlyweight{}
	unshared.operation("Extrinsic State 3")
}

4. 总结

享元模式 是一种用于性能优化的设计模式,通过共享尽可能多的对象来有效支持大量细粒度的对象。这种模式特别适用于那些对象数量巨大且大部分状态可以外部化的情况。

主要优点
  1. 减少了内存的使用:通过共享对象,减少了内存的占用,特别是在对象数量庞大的情况下。
  2. 提高了性能:减少了对象的创建和销毁,提高了应用程序的性能。
  3. 支持大规模的应用程序:适合于需要处理大量对象的应用程序,如图形界面、文档编辑器等。
主要缺点
  1. 增加了系统的复杂性:为了管理和共享对象,系统会变得更加复杂。
  2. 内部状态和外部状态的分离:需要明确区分哪些状态是内部的,哪些是外部的,这可能会增加开发的难度。
适用场景
  • 当一个应用程序使用了大量的对象,而这些对象的部分状态可以外部化时。
  • 当需要使用大量的相似对象,而这些对象的大多数状态都可以外部化时。
  • 当对象的大部分状态都可以转换成外部状态时,使用享元模式可以显著减少内存的占用。

http://www.kler.cn/a/413259.html

相关文章:

  • 实验三 z变换及离散时间LTI系统的z域分析
  • 【pyspark学习从入门到精通22】机器学习库_5
  • spring boot框架漏洞复现
  • Python学习第十三天--面向对象,类和对象
  • ⭐️ GitHub Star 数量前十的工作流项目
  • gRPC 双向流(Bidirectional Streaming RPC)的使用方法
  • 八、利用CSS制作导航栏菜单的习题
  • Easyui 实现订单拆分开票功能
  • 算法新篇章:AI如何在数学领域超越人类
  • 【CSS in Depth 2 精译_061】9.4 CSS 中的模式库 + 9.5 本章小结
  • python的openpyxl库设置表格样式:字体/边框/对齐/颜色等
  • ES6中,Set和Map的区别 ?
  • DFS练习题 ——(上)
  • CentOS8.5.2111(7)完整的Apache综合实验
  • maxun爬虫工具docker搭建
  • Java八股(一)
  • 问:Spring JavaConfig怎么用?
  • mybatis-plus 实现分页查询步骤
  • 【设计模式】创建型模式之装饰器模式(组成、步骤、优缺点、场景)
  • 群聊前选择患者功能的实现
  • Vue集成Excalidraw实现在线画板功能
  • ELK配置索引清理策略
  • ts 非空断言
  • 跨平台应用开发框架(2)----Qt(窗口篇)
  • Linux 下自动化之路:达梦数据库定期备份并推送至 GitLab 全攻略
  • 开箱即用!合合信息的智能文档处理“百宝箱”