设计模式之享元模式

设计模式 -- 享元模式(Flyweight Pattern) 使用共享对象可以有效的支持大量的细粒度对象。 应用场景 主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。例如:缓存,对象池;Android中: Message.obtain通过重用Message对象来避免大量的Message对象被频繁的创建和销毁。 FlyWeightFactory负责创建和管理享元单元,当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象,FlyWeigh 阅读详情

引言

家人们,谁懂啊,一觉醒来,我竟然重生了,摇身一变成了共享书店老板。最近有本神书爆火,叫《重生之霸道总裁学习设计模式拯救小娇妻》,一听这书名,妥妥的爆款预定。我这商业头脑瞬间被激活,毫不犹豫直接豪购一万本,堆在我的豪华仓库里,当时我就觉得自己简直是商业鬼才,下一个巴菲特非我莫属!
为了高效管理这些书,我翻出了祖传的图书管理系统。看着那系统界面,一个个录入书的信息,这不得把我手累废?我这程序员天赋瞬间觉醒,直接在后台敲起代码,一个 for 循环,“唰唰唰” 就 new 出一万个对象,把封面、页数、作者这些元数据一股脑全存进去了。当时我就想,我要是重生当程序员,那肯定是业界天花板,年薪百万不是梦!
没过多久,一群帅气多金的顾客涌进我的书店,清一色都要借这本《重生之霸道总裁学习设计模式拯救小娇妻》。看着书一本本借出去,租金数字蹭蹭往上涨,我笑得嘴角都快咧到后脑勺了。然而,乐极生悲啊家人们!就在我给一本书录入借阅状态的时候,“啪” 的一下,跟放鞭炮似的,系统毫无征兆地崩了!我当时就傻眼了,眼泪 “唰” 地一下就出来了,这不是玩我嘛!我捂着眼大喊:“停停停,这像话吗?” 这年轻的系统可真是不讲武德,说崩就崩,一点面子都不给!
没办法,我只能麻溜地把书店关了,赶紧排查系统问题。这不查不知道,一查吓一跳,祖传系统那小身板,内存直接爆了!我一拍脑门才反应过来,那一万个对象,每个都存着一样的元数据,再一个个录借阅信息,内存不爆才怪。我对着这些对象在心里喊:“你们耗子尾汁,好好反思反思!” 我就琢磨着,这些对象一开始都一模一样,就后面借阅信息不同,能不能就用一个原始对象,根据借阅信息来区分它们呢?嘿,这就引出了咱们今天要深入研究的设计模式 ——享元模式(Flyweight) !

故事纯属虚构,请勿当真,谁家好人做的管理系统不用数据库来持久化,直接写内存的?

概念

定义

享元模式是一种结构型设计模式,主要用于减少创建对象的数量,以降低内存占用和提高性能。

它通过共享已经存在的对象来避免创建重复的对象,这些被共享的对象称为享元。享元模式的核心思想是将对象的状态分为内部状态和外部状态,内部状态是可以共享的部分,通常是不变的,与对象的上下文无关;外部状态则是不可共享的部分,会随环境变化而变化,在使用享元对象时由客户端传入。

结构

  • 享元工厂(Flyweight Factory):负责创建和管理享元对象。它维护一个享元池,用于存储已经创建的享元对象。当客户端请求一个享元对象时,享元工厂首先检查享元池中是否已经存在该对象,如果存在,则直接返回;如果不存在,则创建一个新的享元对象并放入享元池中。
  • 抽象享元(Flyweight):定义了享元对象的公共接口,所有具体享元类都必须实现这个接口。这个接口通常包含一个方法,用于接收外部状态并根据内部状态和外部状态进行相应的操作。
  • 具体享元(Concrete Flyweight):实现了抽象享元接口,是实际被共享的对象。它包含了内部状态,并实现了在接收外部状态后进行操作的具体逻辑。
  • 非共享具体享元(Unshared Concrete Flyweight):在某些情况下,可能存在一些与享元对象结构相似,但不适合共享的对象,它们就是非共享具体享元。这些对象通常包含一些无法共享的状态或行为。

在这里插入图片描述

设计原则

单一职责原则

享元模式中,各类职责明确。享元工厂负责创建、管理享元对象;抽象享元定义通用行为;具体享元实现行为并处理内部状态,非共享具体享元处理非共享状态。这样让类功能清晰,降低耦合,便于维护和测试。

开闭原则

享元模式对扩展开放,对修改封闭。新增具体享元类型时,创建新类实现抽象享元接口即可,无需修改现有享元工厂和其他享元类,保证系统可扩展性和稳定性。

里氏替换原则

具体享元类作为抽象享元类的子类,能完全替换父类在系统中的位置,且不影响系统功能。具体享元类要实现抽象享元类的方法,保持语义和行为不变,保障代码继承关系稳定,提高复用性与可维护性。

依赖倒置原则

享元模式里,高层模块(如客户端)依赖抽象享元类,而非具体享元类。享元工厂也通过抽象享元类管理、提供对象。这降低模块耦合,让系统更灵活,具体享元类实现变化时,只要抽象接口不变,高层模块就无需修改。

接口隔离原则

抽象享元类接口应最小化,只含具体享元类必实现的方法,避免具体享元类实现无关方法,提升系统内聚性,降低耦合,让具体享元类更专注、灵活,易于维护。

示例

我们以引言中的例子编写示例代码。

在这个例子中,各个部分与享元模式的对应关系如下:

  1. 书:可以看作是享元对象,书中的元数据(封面、页数、作者等)是内部状态,这些信息在所有书籍实例中是相同的,可以共享。
  2. 图书管理系统:包含享元工厂和相关的管理逻辑。
  3. 书的借阅状态、书的编号:外部状态,每本书的编号、借出时间,借出对象等是不同的,不能共享。

类图

在这里插入图片描述

C++实现

#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>

// 抽象享元类
class BookInterface {
public:
  virtual void printInfo() const = 0;
  virtual ~BookInterface() = default;
};

// 具体享元类,存储书的内部状态
class Book : public BookInterface {
private:
  std::string isbn;
  std::string title;
  std::string author;
  int pages;

public:
  Book(const std::string &isbn, const std::string &title,
       const std::string &author, int pages)
      : isbn(isbn), title(title), author(author), pages(pages) {}
  void printInfo() const override {
    std::cout << "ISBN: " << isbn << ", Title: " << title
              << ", Author: " << author << ", Pages: " << pages << std::endl;
  }
};

// 享元工厂类
class BookFactory {
private:
  std::unordered_map<std::string, std::shared_ptr<BookInterface>> books;

public:
  std::shared_ptr<BookInterface> getBook(const std::string &isbn,
                                         const std::string &title,
                                         const std::string &author, int pages) {
    if (books.find(isbn) == books.end()) {
      books[isbn] = std::make_shared<Book>(isbn, title, author, pages);
    }
    return books[isbn];
  }
};

// 非共享具体享元类,存储书的外部状态
class BookInstance {
private:
  std::shared_ptr<BookInterface> book;
  std::string bookId;
  std::string borrower;
  std::string borrowDate;

public:
  BookInstance(const std::shared_ptr<BookInterface> &book,
               const std::string &bookId, const std::string &borrower,
               const std::string &borrowDate)
      : book(book), bookId(bookId), borrower(borrower), borrowDate(borrowDate) {
  }
  void printInfo() const {
    book->printInfo();
    std::cout << "Book ID: " << bookId << ", Borrower: " << borrower
              << ", Borrow Date: " << borrowDate << std::endl;
  }
};

int main() {
  BookFactory factory;
  // 创建享元对象
  auto book1 =
      factory.getBook("123-4-56-789123-0",
                      "重生之霸道总裁学习设计模式拯救小娇妻", "总裁大人", 395);
  // 创建书的外部状态
  BookInstance instance1(book1, "001", "Alice", "2023-10-01");
  BookInstance instance2(book1, "002", "Bob", "2023-10-02");
  // 打印信息
  instance1.printInfo();
  instance2.printInfo();
  return 0;
}

Java实现

import java.util.HashMap;
import java.util.Map;

// 抽象享元接口
interface BookInterface {
  void printInfo();
}

// 具体享元类,存储书的内部状态
class Book implements BookInterface {
  private final String isbn;
  private final String title;
  private final String author;
  private final int pages;
  public Book(String isbn, String title, String author, int pages) {
    this.isbn = isbn;
    this.title = title;
    this.author = author;
    this.pages = pages;
  }
  @Override
  public void printInfo() {
    System.out.println("ISBN: " + isbn + ", Title: " + title +
                       ", Author: " + author + ", Pages: " + pages);
  }
}

// 享元工厂类
class BookFactory {
  private final Map<String, BookInterface> books = new HashMap<>();
  public BookInterface getBook(String isbn, String title, String author,
                               int pages) {
    return books.computeIfAbsent(isbn,
                                 k -> new Book(isbn, title, author, pages));
  }
}

// 非共享具体享元类,存储书的外部状态
class BookInstance {
  private final BookInterface book;
  private final String bookId;
  private final String borrower;
  private final String borrowDate;
  public BookInstance(BookInterface book, String bookId, String borrower,
                      String borrowDate) {
    this.book = book;
    this.bookId = bookId;
    this.borrower = borrower;
    this.borrowDate = borrowDate;
  }
  public void printInfo() {
    book.printInfo();
    System.out.println("Book ID: " + bookId + ", Borrower: " + borrower +
                       ", Borrow Date: " + borrowDate);
  }
}

// 主类
public class FlyweightPatternExample {
  public static void main(String[] args) {
    BookFactory factory = new BookFactory();
    // 创建享元对象
    BookInterface book1 = factory.getBook(
        "123-4-56-789123-0", "重生之霸道总裁学习设计模式拯救小娇妻", "总裁大人",
        395);
    // 创建书的外部状态
    BookInstance instance1 =
        new BookInstance(book1, "001", "Alice", "2023-10-01");
    BookInstance instance2 =
        new BookInstance(book1, "002", "Bob", "2023-10-02");
    // 打印信息
    instance1.printInfo();
    instance2.printInfo();
  }
}

代码解释

  1. BookInterface类:这是一个抽象类(或接口),定义了printInfo()方法,作为抽象享元类。
  2. Book类:继承自BookInterface类,实现了printInfo()方法,包含书的内部状态(isbn、title、author、pages),是具体享元类。
  3. BookFactory类:负责创建和管理Book对象,通过getBook()方法返回BookInterface类型的智能指针,与BookInterface存在创建关系。
  4. BookInstance类:包含书的外部状态(bookId、borrower、borrowDate),持有一个BookInterface类型的智能指针,与BookInterface存在使用关系。

享元模式流程说明

1. 定义抽象享元与具体享元

  • 抽象享元(Flyweight):定义一个抽象接口,该接口声明了享元对象需要实现的操作。这个接口是所有具体享元类的公共规范,通常包含一个可以接收外部状态作为参数的方法,用于根据内部状态和传入的外部状态执行具体操作。
  • 具体享元(Concrete Flyweight):实现抽象享元接口,包含对象的内部状态。内部状态是对象的固有属性,不随环境变化而改变,可在多个客户端之间共享。例如,在图形绘制系统中,颜色和形状等信息可以作为内部状态。

2. 创建享元工厂

  • 享元工厂(Flyweight Factory):负责创建和管理享元对象。它维护一个享元池(通常是一个集合,如哈希表),用于存储已经创建的享元对象。享元工厂提供一个获取享元对象的方法,该方法接收一个标识(如键值)作为参数,用于查找或创建特定的享元对象。

3. 客户端请求享元对象

  • 客户端向享元工厂请求一个享元对象,同时传入一个标识(键值)。这个标识用于唯一标识客户端需要的享元对象类型或具体实例。

4. 享元工厂处理请求

  • 检查享元池:享元工厂接收到客户端的请求后,首先检查享元池中是否已经存在具有该标识的享元对象。
  • 返回现有对象:如果享元池中存在该对象,享元工厂直接从享元池中取出该对象并返回给客户端。
  • 创建新对象:如果享元池中不存在该对象,享元工厂会创建一个新的具体享元对象,并将其添加到享元池中,然后返回该新对象给客户端。

5. 客户端使用享元对象

  • 客户端获取到享元对象后,将外部状态作为参数传递给享元对象的方法进行调用。外部状态是随环境变化而变化的状态,由客户端在使用时传入。例如,在图形绘制系统中,位置信息可以作为外部状态。
  • 享元对象根据自身的内部状态和客户端传入的外部状态执行相应的操作,并将结果返回给客户端。

享元模式的优缺点

优点

1. 减少内存占用

享元模式的核心优势之一就是显著减少内存的使用量。在系统中,如果存在大量相似的对象,这些对象的部分状态是相同的(内部状态),将这些相同的状态提取出来并共享,可以避免为每个对象都重复存储这些相同的信息。例如,在一个图形绘制系统中,有大量的圆形对象,这些圆形的颜色、半径等属性可能是相同的,使用享元模式可以将这些相同的属性作为内部状态共享,只创建一个包含这些属性的对象,而不是为每个圆形都创建一个完整的对象,从而大大降低了内存的占用。

2. 提高性能

由于减少了对象的创建数量,系统在运行过程中创建和销毁对象的开销也随之减少。对象的创建和销毁是比较耗时的操作,尤其是在创建大量对象时,会对系统性能产生较大影响。享元模式通过共享对象,避免了重复创建相同的对象,减少了系统的开销,提高了系统的响应速度和运行效率。同时,共享对象的复用也减少了垃圾回收的压力,进一步提升了性能。

3. 增强可维护性和可扩展性

享元模式将对象的状态分为内部状态和外部状态,使得代码的结构更加清晰。内部状态集中管理,外部状态由客户端在使用时传入,这种分离方式使得代码的逻辑更加清晰,易于理解和维护。当需要对享元对象进行修改或添加新的功能时,只需要在相应的具体享元类中进行操作,不会影响到其他部分的代码,提高了代码的可维护性。此外,当需要增加新的享元对象类型时,只需要创建新的具体享元类并实现抽象享元接口,而不需要对现有代码进行大规模修改,具有良好的可扩展性。

4. 遵循设计原则

享元模式遵循了一些重要的设计原则,如单一职责原则、开闭原则等。具体享元类只负责处理内部状态和实现抽象享元接口定义的方法,职责明确;对扩展开放,对修改封闭,当需要添加新的享元对象类型时,只需要扩展具体享元类,而不需要修改现有代码。

缺点

1. 增加系统复杂性

享元模式需要将对象的状态进行分离和管理,这增加了系统的设计和实现难度。开发人员需要仔细区分对象的内部状态和外部状态,并确保外部状态在使用时正确传递给享元对象。同时,享元工厂的管理也需要一定的成本,需要考虑享元对象的创建、销毁和维护等问题,这使得系统的结构变得更加复杂,增加了开发和维护的成本。

2. 可能不适用于所有场景

享元模式并不适用于所有情况。对于那些对象状态差异较大,难以区分内部状态和外部状态的场景,或者共享对象带来的收益不明显的场景,使用享元模式可能会增加不必要的复杂性,而不会带来明显的性能提升。例如,如果对象的状态大部分都是不同的,共享的部分很少,那么使用享元模式可能会得不偿失。

3. 维护外部状态的复杂性

由于享元对象的部分状态是外部传入的,客户端需要正确地维护这些外部状态,确保享元对象在不同的上下文环境中能够正确地工作。这可能会增加客户端代码的复杂性和维护成本。如果外部状态管理不当,可能会导致享元对象的行为出现异常,影响系统的正确性。

4. 线程安全问题

在多线程环境下使用享元模式时,需要考虑线程安全问题。如果多个线程同时访问和修改享元对象的状态,可能会导致数据不一致的问题。需要采取适当的同步机制来保证线程安全,这进一步增加了系统的复杂性。

注意事项

状态区分与管理

  • 清晰划分内部和外部状态
    • 内部状态是可共享且不随环境变化的部分,外部状态则会根据使用场景而改变。必须准确区分这两种状态,否则会影响享元模式的效果。例如在一个文本排版系统中,字符的字体、字号属于内部状态,而字符在页面上的位置则是外部状态。
    • 若状态划分错误,将本应作为外部状态的部分也共享,会导致不同使用场景下出现数据错误;若将内部状态作为外部状态处理,则无法实现对象共享,失去了享元模式节省内存的优势。
  • 外部状态的正确传递
    • 由于享元对象依赖客户端传入外部状态来完成具体操作,所以客户端要确保在调用享元对象方法时,正确传递所需的外部状态。比如在一个图形绘制系统中,当使用共享的圆形对象绘制不同位置的圆时,要准确传入圆心坐标等外部状态。
    • 如果外部状态传递错误或不完整,可能会使享元对象的行为不符合预期,导致系统出现逻辑错误。

享元工厂的管理

  • 线程安全问题
    • 在多线程环境下,享元工厂负责创建和管理享元对象,可能会出现多个线程同时请求创建相同享元对象的情况。如果不进行同步控制,可能会导致重复创建对象,破坏享元模式的共享机制。
    • 可以使用同步锁等机制来保证线程安全。例如在 Java 中,可以使用synchronized关键字或ReentrantLock来对享元工厂的创建对象方法进行同步。
  • 享元池的维护
    • 享元工厂通常使用一个享元池(如哈希表)来存储已创建的享元对象。随着系统运行,享元池中的对象可能会越来越多,占用大量内存。因此需要考虑对享元池进行合理的维护,例如设置对象的最大数量,当达到上限时进行对象的清理操作。
    • 同时,要注意清理策略的合理性,避免误删正在使用的对象。比如可以采用引用计数或定时清理等方式。

系统复杂性与性能权衡

  • 增加的系统复杂度
    • 享元模式将状态分离、引入享元工厂等操作,会增加系统的设计和实现复杂度。开发人员需要花费更多的精力来理解和维护代码,尤其是在状态管理和对象交互方面。
    • 在决定是否使用享元模式时,需要权衡系统复杂度的增加与节省内存、提高性能带来的收益。如果系统中相似对象数量较少,使用享元模式可能会得不偿失。
  • 性能开销
    • 虽然享元模式的初衷是提高性能,但在某些情况下,也可能会引入额外的性能开销。例如,享元工厂在查找和创建对象时,需要进行哈希查找等操作,这会带来一定的时间开销。
    • 要确保享元模式的使用不会成为系统的性能瓶颈,在设计和实现过程中进行性能测试和优化。

可维护性和扩展性

  • 代码的可维护性
    • 由于享元模式涉及多个类和复杂的状态管理,代码的可维护性可能会受到影响。在修改或扩展享元对象的功能时,需要仔细考虑对整个系统的影响,避免引入新的问题。
    • 可以通过良好的代码注释、模块化设计等方式来提高代码的可维护性。
  • 系统的扩展性
    • 当需要增加新的享元对象类型或修改享元对象的内部状态时,要确保系统具有良好的扩展性。例如,在享元工厂中添加新的对象创建逻辑时,要尽量减少对现有代码的修改。
    • 可以采用面向接口编程、遵循开闭原则等设计思想来提高系统的扩展性。

享元模式与单例模式的对比

对比维度享元模式单例模式
设计目的减少内存占用和提高性能,通过共享相似对象实现确保一个类在系统中只有一个实例,并提供全局访问点
对象数量可存在多个享元对象,相同内部状态的对象共享实例整个系统生命周期内,一个类仅一个实例
状态管理将对象状态分为内部(可共享)和外部(随环境变)状态不区分内外部状态,单例对象自身管理状态
应用场景适用于大量细粒度且部分状态可共享的对象场景,如文本编辑、图形处理适用于需确保唯一实例且全局访问的场景,如数据库连接池、日志记录器
实现方式依赖享元工厂创建和管理享元对象,使用享元池存储对象有饿汉式、懒汉式等多种实现,懒汉式需考虑线程安全

应用场景

存在大量相似对象

当系统中存在大量细粒度的对象,并且这些对象具有很多相同的属性时,使用享元模式可以显著减少内存的使用。例如在一个文本编辑软件中,会有大量的字符对象,这些字符可能具有相同的字体、字号、颜色等属性。通过享元模式,将这些相同的属性作为内部状态进行共享,避免为每个字符都创建一个包含所有属性的完整对象,从而节省大量内存。

内存资源紧张

如果系统的内存资源有限,而又需要处理大量的对象,享元模式是一个很好的解决方案。它通过共享对象,减少了对象的创建数量,降低了内存占用。比如在一些嵌入式系统或者移动应用中,内存资源相对较少,使用享元模式可以优化系统性能,避免因内存不足导致的系统崩溃或运行缓慢。

对象状态可区分

能够清晰地将对象的状态分为内部状态和外部状态是使用享元模式的关键条件。内部状态是对象的固有属性,不随环境变化而改变,可以被多个对象共享;外部状态则随环境变化而变化,由客户端在使用时传入。例如在一个图形绘制系统中,图形的颜色、形状等属性可以作为内部状态共享,而图形的位置、大小等属性可以作为外部状态由客户端根据具体需求进行设置。

系统性能要求高

频繁创建和销毁对象会消耗大量的系统资源,影响系统的性能。享元模式通过共享对象,避免了重复创建相同的对象,减少了对象创建和销毁的开销,从而提高了系统的性能。特别是在对性能要求较高的实时系统、游戏开发等领域,享元模式可以显著提升系统的响应速度和运行效率。

多次重复使用相同对象

如果某些对象在系统中会被多次重复使用,使用享元模式可以提高对象的复用率。例如在一个数据库连接池中,数据库连接对象会被多个数据库操作重复使用,通过享元模式将这些连接对象进行共享,可以避免频繁创建和关闭数据库连接,提高数据库操作的性能。

【Java设计模式】Java设计模式之(二十三)享元模式(Flyweight Pattern) 本文目录 一、组合模式介绍 1.1 含义 1.2 适用场景 1.3 主要解决 1.4 应用实例 1.5 优缺点 二、组合模式实现 2.1 类图 2.2 角色分析 2.3 代码实现 三、源码分析 这种类型的设计模式属于结构型模式。 一、组合模式介绍 1.1 含义 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。 享元模式尝试重用现有的同类对 阅读详情

相关推荐

Matlab GUIDE -- 串口操作

1、首先新建-->应用程序-->GUIDE。 2、绘制一个简单的UI。 3、然后右击“打开串口”图标-->查看回调-->callback,即可打开此图标的回调函数,此回调函数是press button时执行(可按需要选择其他回调)。 4、在回调函数中添加打开串口的代码。 delete(instrfindall); %删除所有串口 s3 = serial('CO

Asgard-X 2837

23种设计模式之享元模式(Flyweight Pattern)

本篇文章将23种设计模式中的享元模式,此篇文章为一天学习一个设计模式系列文章,后面会分享其他模式知识。

小威的博客 2万+

用OpenCV+ROS实现焊接机器人智能纠偏:线激光视觉的算法调参全流程

本文详细介绍了基于OpenCV和ROS的焊接机器人智能纠偏系统全流程。通过线激光视觉系统实时感知焊缝,重点解析了抗干扰图像预处理、改进的Steger算法提取激光条纹中心线,以及从2D像素到机器人基坐标系的完整坐标变换。该系统为应对焊接飞溅、弧光等复杂工况,实现高精度实时路径纠偏提供了从算法优化到工程集成的完整解决方案。

vodka的博客 158

23种设计模式——享元模式(Flyweight Pattern)

本文介绍了23种经典设计模式之——享元模式(Flyweight Pattern)的使用及说明

Meteors.的博客 1345

Win11上从零跑通Carla自动驾驶仿真:保姆级环境配置与避坑指南(Python 3.7+)

本文详细介绍了在Win11系统上从零配置Carla自动驾驶仿真环境的完整流程,包括Python 3.7+环境搭建、依赖安装、常见问题排查及性能优化技巧。通过保姆级教程帮助开发者快速避坑,实现稳定的自动驾驶仿真测试环境部署。

weixin_33488239的博客 420

AI 大模型接口太零散?自建私有模型管理平台统一整合,管理使用超方便!(支持飞牛nas、群晖nas等服务器快速部署)

面对多种 AI 大模型接口难统一、管理繁琐的问题🤯,本文分享一款超实用开源网关工具⚡,可聚合各大模型、自动转接口、支持可视化管理,Docker 一键部署,大幅降低开发与维护成本🚀

XiaoqiangClub的博客 266

设计模式之享元模式(Flyweight Design Pattern)

享元模式是八种结构型模式之一,享元就是共享单元(元素)的意思,可以理解是共享对象。享元模式的用途就是复用对象,节省内存。 如何使用享元模式,用棋牌室举例。 斗地主相信很多人都玩过,一副版,黑红花方四色,每一色都有从2到A的13张牌,加上大小王,共有54张牌。假如一张牌就是一个对象,一张桌子就要54个对象;一个牌室300张桌子;一个服务器有50个牌室;这样的服务器可能又有200个。那这样的对象就是54*300*50*200=162000000个。 ...

xjj1314的专栏 350

大语言模型在金融风险预警中的推理应用探索

金融行业一直面临着各种风险,如信用风险、市场风险、操作风险等。准确及时的风险预警对于金融机构的稳定运营和投资者的利益保护至关重要。传统的金融风险预警方法主要基于结构化数据和统计模型,虽然在一定程度上能够识别风险,但对于非结构化数据的处理能力有限,难以捕捉到复杂的风险因素和潜在的风险趋势。大语言模型作为自然语言处理领域的重要突破,具有强大的语言理解和生成能力,能够处理各种形式的文本数据。

AI天才研究院 1169

设计模式-享元模式(Flyweight Pattern)

享元模式 定义 Use sharing to support large numbers of fine-grained objects efficiently. 使用共享对象可有效地支持大量的细粒度的对象。 类型 结构型。 适用场景 在对象(相同或相似的对象)足够多的时候,而创建这些对象造成了很大的系统开销时,应该考虑使用享元模式。 享元有被频繁使用的场景,才有使用享元模式的价值,因为,在...

kaven 4493

uniapp - 详解使用高德地图在地图上实现绘制边界/点聚合/行政区域高亮等功能,Uniapp高德地图点聚合标记及绘制点线面示例代码(全端兼容H5网页、小程序、安卓app、苹果app、nvue)

uni-app,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,高德地图,uniAPP高德地图实现点聚合,地图区域描边、点标记、点信息详情弹窗,实现绘制边界区域,uniapp H5使用高德地图实现点聚合、行政区域高亮,实现高德地图的marker聚合功能,高德地图进行marker标点,点信息展示,点击标记点弹出对话框,点击聚合点后显示信息模态框,打标点,【Uniapp】高德地图的接入自定义标点与信息窗体使用,绘制行政区域边界,绘制多边形,电子围栏,高德行政区划边界,

✅ 精选推荐文章 1万+

paddlehub无法安装,安装报错【Bug完美解决】

paddlehub无法安装,安装报错【Bug完美解决】 我们正在进行一个基于Python的项目开发,该项目需要集成PaddleHub,以利用其丰富的深度学习模型和工具。PaddleHub提供了一种简便的方式来使用预训练模型,以加速开发过程并提高模型效果。 现在paddlehub安装出现问题了,本文彻底解决paddlehub无法安装的问题。

一键难忘的博客 3387

设计模式:享元模式(Flyweight Pattern)

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。

TechNomad的博客 852

华为OD机试 - 单词倒序(Python/JS/C/C++ 2025 A卷 100分)

华为OD机试 2025A卷题库疯狂收录中,刷题。

学Java,找哪吒 1226

秒懂设计模式之享元模式(Flyweight Pattern)

[版权申明] 非商业目的注明出处可自由转载 博文地址: 出自:shusheng007 设计模式汇总篇,一定要收藏: 永不磨灭的设计模式(有这一篇真够了,拒绝标题党) 文章目录概述类型难度定义使用场景UML类图实例第一步,定义一个共享对象通用的接口第二步,实现需要共享的对象类第三步,共享对象工厂第四步,客户端使用技术要点总结优缺点优点缺点总结 概述 也许你会觉得享元模式比较陌生,但是相信在你的软件开发生涯中应该不知不觉的用了很多次,只是你没有总结。例例如你肯定用到过缓存,用到过对象池… 不知道作为IT猿的.

ShuSheng007的程序人生 2340

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

彻底搞懂设计模式DesignPattern-享元模式

对原理图的说明-即(模式的角色及职责) FlyWeight是抽象的享元角色,他是产品的抽象类,同时定义出对象的外部状态和内部状态的接囗或实现 2)ConcreteFlyWeight是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务 UnSharedconcreteFlyWeight是不可共享的角色,一般不会出现在享元工厂 FlyWeight Factory享元工厂类,用于构建一个池客器(集合),同时提供从池中获取对象方法 ...

Ping 291

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

设计模式-10享元模式Flyweight Pattern

摘要:享元模式是一种结构型设计模式,通过共享相似对象来减少内存消耗和提高性能。它适用于系统中有大量相似对象且大多数状态可外部化的场景。模式包含享元接口、具体享元类、享元工厂和客户端四个主要部分。文中提供了两种实现示例:文本编辑器中的字符共享和图形渲染中的树对象共享,展示了如何通过工厂管理共享对象,显著减少实际创建的对象数量。

d3y1`5 81_09 960

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【设计模式】——享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种对象结构型模式,它通过共享已经存在的对象来减少内存使用量和提高系统性能。享元模式特别适用于那些创建大量相似对象而导致内存消耗过大的场景。本文将详细介绍享元模式在C++中的实现和应用。

J^T的博客 2693

Android设计模式之享元模式(Flyweight Pattern)

一 享元模式介绍:1.1 使用享元模式有什么好处? 享元模式是对象池的一种实现,主要目的是用来尽可能减少内存使用量。适合于存在大量重复对象的场景,来缓存可共享的对象,达到对象共享,避免创建过多对象的效果,这样可以提升性能。1.2 关于享元对象? 享元对象中的部分状态可以共享,可以共享的状态为内部状态(内蕴状态),内部状态不会随环境变化,不可共享的状态是外部状态(外蕴状态),外部状态随外部环境

happy_horse的博客 1989

DesignPattern-享元模式

享元模式:String常量池,数据库连接池,缓冲池等等都是享元模式的应用。 每次创建字符创对象时候,都需要创建一个新的字符串对象的话,内存开销很大,所以如果第一次创建了字符串对象hunter,下次在创建相同的字符串hunter时,只是把它的引用再次指向hunter,这样就实现了hunter字符串内内存中的共享。 角色: Flyweight:抽象享元类,所有具体享元类的超类or接口, Concret...

其实我也没有太多期盼,毕竟一生太短,少有圆满 163

设计模式-享元模式/Flyweight Pattern

设计模式-享元模式 参考资料:尚硅谷设计模式. 参考资料: 菜鸟设计模式. 萌新码农 摘自网络资源 + 自己的思考 若有错误请大佬们指点 参考资料网上重复篇章多 忘了参考了哪几位博主的文章 若有侵权 请私信 看到会加上链接 设计模式-享元模式设计模式-享元模式基本介绍内部状态和外部状态类图实例说明 基本介绍 享元模式(Flyweight Pattern)也叫蝇量模式:运用共享技术有效地支持大量细粒度的对象 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象

qq_34883222的博客 407

C++设计模式——享元模式(flyweight pattern)

# 一、原理讲解 ## 1.1意图 运用共享技术有效地支持大量细粒度的对象。 ## 1.2应用场景 - 一个程序中使用了大量的对象; - 完全由于使用大量的对象造成很大的存储开销; - 对象的大多数状态都可变为外部状态; - 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象; - 应用程序不依赖于对象标识。 ## 1.3结构图(UML图) ![享元模式UML结构图](https://img-blog.csdnimg.cn/20200902222642384.jpg?x-oss-

净无邪博客 547

设计模式之享元模式详解(FlyWeight Pattern)

基本介绍 享元模式(Flyweight Pattern) 也叫 蝇量模式: 运用共享技术有效地支持大量细粒度的对象 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池...

Superman_peng的博客 641

【设计模式】享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)又被称作轻量级模式、蝇量模式,它经典的体现就是对象池。享元模式的根本目的就是"共享单元",让对象能够共享复用,就像共享单车一样,路人甲(客户程序A)骑完路人丙(客户程序B)用,以此减少内存占用。

櫆溟的博客 487

设计模式 享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种结构型设计模式,它的目的是通过共享技术来有效地支持大量细粒度的对象。享元模式可以极大地减少内存的使用,从而提高程序的性能。它特别适用于需要创建大量相似对象的场景,通过共享不变的部分来减少对象的数量和内存消耗。具体享元模式实现FlyweightInterface接口, 查看内外部状态。通过 Map 存储之前对象,获取之前的对象无需重新创建。定义 flyweight 的接口。

ling_zhi_xin的博客 1050

设计模式教程:享元模式(Flyweight Pattern)

通过共享相同的对象来减少内存的消耗,常用于大量相似对象的场景。

遇见伯灵说的博客 1055

Java 设计模式之享元模式(Flyweight Pattern)

旨在通过共享对象来有效支持大量细粒度对象的复用,从而减少内存占用和提高性能。假设需要绘制大量树(Tree)对象,树的类型(名称、颜色)可共享,位置和年龄为外部状态。类的常量池是享元模式的典型实现,相同字面量的字符串对象被复用。,适用于存在大量重复对象且对象的大部分状态可以外部化的场景。:通过共享内部状态减少对象数量,外部状态由客户端传递。:存在大量相似对象且内存占用是瓶颈时优先考虑。:享元工厂管理共享对象池,确保唯一性。:字符的字体、颜色、大小。:字符在文档中的位置。:子弹的位置、速度。

guanxin0206的博客 730
上一篇: 设计模式之外观模式
下一篇: 设计模式之代理模式
LiaoYuan.Dai
博客等级 码龄7年 247粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值