• 设计模式——11. 享元模式


    1. 说明

    享元模式(Flyweight Pattern)是一种结构型设计模式,它旨在减少系统中相似对象的内存占用或计算开销,通过共享相同的对象来达到节省资源的目的。
    享元模式的核心思想是将对象的状态分为内部状态(Intrinsic State)和外部状态(Extrinsic State):

    • 内部状态是对象可以共享的部分,它通常存储在享元对象内部,并且不随外部环境的变化而变化。这些状态被多个对象共享。
    • 外部状态是对象的一部分,但它不会被共享,它随着外部环境的变化而变化。

    通过将内部状态和外部状态分离,享元模式使得可以共享内部状态的多个对象共享同一个享元对象,从而减少了内存占用和提高了系统性能

    享元模式提供了一种高效地共享对象的方式,从而减少了内存占用和提高了性能,但需要注意的是,使用享元模式会增加系统的复杂性,因为它需要维护共享对象池。

    #2. 使用的场景

    享元模式在以下情况下可以考虑使用:

    1. 大量相似对象:当一个应用程序需要创建大量相似的对象,而这些对象的区别仅在于它们的外部状态时,可以使用享元模式。通过共享内部状态,可以减少内存消耗,提高性能。
    2. 内部状态和外部状态:如果一个对象的状态可以分为内部状态(可以共享)和外部状态(不可共享),那么可以使用享元模式。内部状态在对象内部管理,而外部状态在对象外部管理,根据需要传递给享元对象。
    3. 缓存:享元模式可以用于实现缓存。例如,在计算密集型应用程序中,可以将计算结果缓存起来,以便在相同输入情况下可以重复使用。
    4. 字形或图标管理:在图形处理软件中,字符、字形或图标通常是相似的,可以使用享元模式来共享它们的共同部分,减少内存占用。
    5. 线程池:线程池可以使用享元模式来管理可重用的线程对象,减少线程的创建和销毁开销。
    6. 游戏开发:在游戏开发中,可以使用享元模式来管理游戏中的角色、道具或粒子效果等。

    总之,享元模式适用于需要创建大量相似对象,并且希望通过共享内部状态来减少内存消耗和提高性能的情况。但要注意,使用享元模式会增加一定的复杂性,因为需要维护共享对象池和处理外部状态的传递。因此,应谨慎选择是否使用享元模式。

    3. 应用例子

    以下是一个使用 Python 实现的简单享元模式示例,模拟了共享电子邮件对象的情况:

    # 抽象享元类
    class Email:
        def __init__(self, content):
            self.content = content
    
        def send(self, recipient):
            pass
    
    # 具体享元类
    class SharedEmail(Email):
        def send(self, recipient):
            print(f"Shared email sent to {recipient} with content: {self.content}")
    
    # 享元工厂类
    class EmailFactory:
        _emails = {}
    
        @classmethod
        def get_shared_email(cls, content):
            if content not in cls._emails:
                cls._emails[content] = SharedEmail(content)
            return cls._emails[content]
    
    # 客户端
    if __name__ == "__main__":
        factory = EmailFactory()
    
        email1 = factory.get_shared_email("Hello, how are you?")
        email2 = factory.get_shared_email("Please review the document.")
        email3 = factory.get_shared_email("Let's meet tomorrow.")
    
        email1.send("user1@example.com")
        email2.send("user2@example.com")
        email3.send("user3@example.com")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这个示例中:

    • Email 是抽象享元类,它包含了一个 send 方法,该方法需要被具体享元类实现。
    • SharedEmail 是具体享元类,它继承了 Email 并实现了 send 方法。这个类表示可以共享的电子邮件对象。
    • EmailFactory 是享元工厂类,负责管理和维护共享的电子邮件对象。它包括一个私有字典 _emails 用于存储已创建的共享电子邮件对象。get_shared_email 方法用于获取或创建共享电子邮件对象。
    • 在客户端代码中,我们使用享元工厂类来获取共享的电子邮件对象,并调用 send 方法发送电子邮件。

    这个示例演示了享元模式的概念,其中多个电子邮件对象共享相同的内容,以减少内存占用。

    4. 实现要素

    享元模式的实现要素包括以下几个部分:

    1. 抽象享元类(Flyweight): 定义了具体享元类的接口,通常包括一个操作方法,该方法的参数中包含外部状态。
    2. 具体享元类(ConcreteFlyweight): 实现抽象享元类的接口,包含内部状态和外部状态。内部状态是可以被多个具体享元对象共享的部分,外部状态是不可共享的部分。
    3. 享元工厂类(FlyweightFactory): 负责管理和维护享元对象,通常包括一个享元对象池。客户端通过工厂类获取具体享元对象,并在需要时传递外部状态。
    4. 客户端(Client): 使用享元对象的客户端,负责维护外部状态,并将外部状态传递给享元对象。

    5. Java/golang/javascrip/C++ 等语言实现方式

    5.1 Java实现

    上述例子用Java语言实现示例如下:

    import java.util.HashMap;
    import java.util.Map;
    
    // 抽象享元类
    interface Email {
        void send(String recipient);
    }
    
    // 具体享元类
    class SharedEmail implements Email {
        private String content;
    
        public SharedEmail(String content) {
            this.content = content;
        }
    
        public void send(String recipient) {
            System.out.println("Shared email sent to " + recipient + " with content: " + content);
        }
    }
    
    // 享元工厂类
    class EmailFactory {
        private Map emails = new HashMap<>();
    
        public Email getSharedEmail(String content) {
            if (!emails.containsKey(content)) {
                emails.put(content, new SharedEmail(content));
            }
            return emails.get(content);
        }
    }
    
    // 客户端
    public class Main {
        public static void main(String[] args) {
            EmailFactory factory = new EmailFactory();
    
            Email email1 = factory.getSharedEmail("Hello, how are you?");
            Email email2 = factory.getSharedEmail("Please review the document.");
            Email email3 = factory.getSharedEmail("Let's meet tomorrow.");
    
            email1.send("user1@example.com");
            email2.send("user2@example.com");
            email3.send("user3@example.com");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    5.2 Golang实现

    上述例子用golang实现示例如下:

    package main
    
    import "fmt"
    
    // Email 是抽象享元接口
    type Email interface {
            Send(recipient string)
    }
    
    // SharedEmail 是具体享元类
    type SharedEmail struct {
            content string
    }
    
    func NewSharedEmail(content string) *SharedEmail {
            return &SharedEmail{content}
    }
    
    func (e *SharedEmail) Send(recipient string) {
            fmt.Printf("Shared email sent to %s with content: %s\n", recipient, e.content)
    }
    
    // EmailFactory 是享元工厂类
    type EmailFactory struct {
            emails map[string]Email
    }
    
    func NewEmailFactory() *EmailFactory {
            return &EmailFactory{
                    emails: make(map[string]Email),
            }
    }
    
    func (f *EmailFactory) GetSharedEmail(content string) Email {
            if email, exists := f.emails[content]; exists {
                    return email
            }
            email := NewSharedEmail(content)
            f.emails[content] = email
            return email
    }
    
    func main() {
            factory := NewEmailFactory()
    
            email1 := factory.GetSharedEmail("Hello, how are you?")
            email2 := factory.GetSharedEmail("Please review the document.")
            email3 := factory.GetSharedEmail("Let's meet tomorrow.")
    
            email1.Send("user1@example.com")
            email2.Send("user2@example.com")
            email3.Send("user3@example.com")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    5.3 Javascript实现

    上述例子用javascript实现示例如下:

    // 抽象享元类
    class Email {
      constructor(content) {
        this.content = content;
      }
    
      send(recipient) {}
    }
    
    // 具体享元类
    class SharedEmail extends Email {
      send(recipient) {
        console.log(`Shared email sent to ${recipient} with content: ${this.content}`);
      }
    }
    
    // 享元工厂类
    class EmailFactory {
      constructor() {
        this.emails = {};
      }
    
      getSharedEmail(content) {
        if (!this.emails[content]) {
          this.emails[content] = new SharedEmail(content);
        }
        return this.emails[content];
      }
    }
    
    // 客户端
    const factory = new EmailFactory();
    
    const email1 = factory.getSharedEmail("Hello, how are you?");
    const email2 = factory.getSharedEmail("Please review the document.");
    const email3 = factory.getSharedEmail("Let's meet tomorrow.");
    
    email1.send("user1@example.com");
    email2.send("user2@example.com");
    email3.send("user3@example.com");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    5.4 C++实现

    上述例子用C++实现如下:

    #include 
    #include 
    
    // 抽象享元类
    class Email {
    public:
        virtual void send(const std::string& recipient) = 0;
    };
    
    // 具体享元类
    class SharedEmail : public Email {
    private:
        std::string content;
    
    public:
        SharedEmail(const std::string& content) : content(content) {}
    
        void send(const std::string& recipient) override {
            std::cout << "Shared email sent to " << recipient << " with content: " << content << std::endl;
        }
    };
    
    // 享元工厂类
    class EmailFactory {
    private:
        std::map emails;
    
    public:
        Email* getSharedEmail(const std::string& content) {
            if (emails.find(content) == emails.end()) {
                emails[content] = new SharedEmail(content);
            }
            return emails[content];
        }
    
        ~EmailFactory() {
            for (auto& pair : emails) {
                delete pair.second;
            }
            emails.clear();
        }
    };
    
    // 客户端
    int main() {
        EmailFactory factory;
    
        Email* email1 = factory.getSharedEmail("Hello, how are you?");
        Email* email2 = factory.getSharedEmail("Please review the document.");
        Email* email3 = factory.getSharedEmail("Let's meet tomorrow.");
    
        email1->send("user1@example.com");
        email2->send("user2@example.com");
        email3->send("user3@example.com");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    6. 练习题

    假设你正在设计一个图书馆资源管理系统。你需要创建一个 Resource 类来表示不同类型的图书和其他资源。每个资源都有一个唯一的编号、标题和作者。然而,一些资源可能是相同的,例如多本相同的书。在这种情况下,你希望共享相同的资源对象,以节省内存。

    要求:

    1. 使用享元模式实现这个图书馆资源管理系统,确保相同的资源在内存中只有一份实例。
    2. 编写一个程序,演示如何创建和管理图书馆资源。

    使用 C++、Java、Python 或任何其他编程语言来实现这个练习。
    你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~

  • 相关阅读:
    java8函数式编程,常用高阶函数处理
    聊聊分布式架构08——SpringBoot开启微服务时代
    数据结构:二叉树与树
    linux网络编程(udp)传输音频
    2022年11月份PMP考试是新版教材吗?
    初识MySQL
    泛型与反射,看这篇就够了
    2.窗口部件-对话框QDialog
    saltstack 企业级实战
    基于JAVA汽车站车辆运管系统计算机毕业设计源码+数据库+lw文档+系统+部署
  • 原文地址:https://blog.csdn.net/guohuang/article/details/133588516