目录
享元模式(Flyweight Pattern):
下面是一个简单的C++代码案例
下面是面试中可能遇到的问题:
享元模式(Flyweight Pattern):
是一种结构型模式,它通过共享对象来减少系统中对象的数量,从而降低系统的内存占用和运行开销。
在享元模式中,通过将对象的内部状态和外部状态分离,将一些共享内部状态的对象设计成享元,即可在系统中共享这些对象,而外部状态则由客户端在使用时传入。这样就可以减少系统中需要创建的对象数量,从而降低内存占用和运行开销。
下面是一个简单的C++代码案例
以图书馆借阅为例,演示如何使用享元模式。
首先定义一个抽象图书类 Book,其中包含了图书的基本信息,如书名、作者、出版社等。
class Book {
public:
virtual void showInfo(const std::string& borrower) = 0;
};
然后定义一个具体的图书类 Novel,它继承自抽象图书类,并实现了 showInfo 方法。
class Novel : public Book {
public:
Novel(const std::string& title, const std::string& author, const std::string& publisher) :
title_(title), author_(author), publisher_(publisher) {}
virtual void showInfo(const std::string& borrower) override {
std::cout << "《" << title_ << "》是" << author_ << "的作品,出版社是" << publisher_ << "。借阅人:" << borrower << std::endl;
}
private:
std::string title_;
std::string author_;
std::string publisher_;
};
接下来定义一个享元工厂类 BookFactory,它负责创建和管理图书对象,同时提供一个借阅方法 borrowBook,该方法接收借阅人的姓名和图书的名称,根据图书名称查找对应的图书对象,将借阅人的姓名作为外部状态传入图书对象的 showInfo 方法中。
class BookFactory {
public:
std::shared_ptr<Book> getBook(const std::string& title) {
auto iter = books_.find(title);
if (iter != books_.end()) {
return iter->second;
} else {
auto book = std::make_shared<Novel>(title, "unknown", "unknown");
books_[title] = book;
return book;
}
}
void borrowBook(const std::string& borrower, const std::string& title) {
auto book = getBook(title);
book->showInfo(borrower);
}
private:
std::unordered_map<std::string, std::shared_ptr<Book>> books_;
};
最后,在 main 函数中使用 BookFactory 创建和管理图书对象,借阅图书。
int main() {
BookFactory bookFactory;
bookFactory.borrowBook("张三", "红楼梦");
bookFactory.borrowBook("李四", "红楼梦");
bookFactory.borrowBook("王五", "水浒传");
bookFactory.borrowBook("赵六", "水浒传");
在上面的代码中,BookFactory 维护了一个图书对象的映射表 books_,其中 key 为图书名称,value 为对应的图书对象。
在 borrowBook 方法中,首先调用 getBook 方法查找对应的图书对象。如果该对象已经存在于映射表中,则直接返回该对象;否则创建一个新的图书对象,并将其添加到映射表中。
然后将借阅人的姓名和图书名称作为外部状态传入图书对象的 showInfo 方法中,该方法根据内部状态(图书的基本信息)和外部状态(借阅人的姓名)生成图书的详细信息,打印出来。
通过使用享元模式,BookFactory 可以共享已经存在的图书对象,避免重复创建对象,从而降低系统内存占用和运行开销。
下面是面试中可能遇到的问题:
问题1:请简单介绍一下享元模式的定义和特点?
答案1:享元模式是一种结构型设计模式,它通过共享对象来减少系统中对象的数量,从而降低系统的内存占用和运行开销。在享元模式中,通过将对象的内部状态和外部状态分离,将一些共享内部状态的对象设计成享元,即可在系统中共享这些对象,而外部状态则由客户端在使用时传入。特点包括:
- 降低系统内存占用和运行开销,特别适用于需要大量创建相似对象的场景。
- 将对象的内部状态和外部状态分离,提高系统的灵活性和可扩展性。
- 享元对象可以被多个客户端共享,但是必须是不可变的,即不能被修改。
问题2:请举例说明什么场景适合使用享元模式?
答案2:享元模式适合在以下场景中使用:
- 当系统需要大量创建相似的对象,且这些对象的内部状态可以共享时,如字体、颜色、图片等。
- 当系统需要缓存大量对象以提高性能时,如线程池、连接池等。
- 当对象的创建和销毁开销较大,但是需要频繁使用时,如数据库连接等。
问题3:请简单描述一下享元模式的实现方式?
答案3:享元模式的实现方式包括以下几个步骤:
- 定义享元类,将对象的内部状态和外部状态分离。
- 定义享元工厂类,用于创建和管理享元对象。
- 在享元工厂类中维护一个对象池,用于缓存已经创建的享元对象。
- 在客户端使用享元对象时,需要将外部状态传入享元对象的方法中。
问题4:请简述一下享元模式的优缺点?
答案4:享元模式的优点包括:
- 可以降低系统内存占用和运行开销。
- 提高系统的灵活性和可扩展性。
- 可以缓存对象,提高系统性能。
缺点包括:
- 需要将对象的内部状态和外部状态分离,增加系统的复杂度。
- 共享对象可能会引入线程安全问题。
- 如果对象池过大,会增加系统的管理开销。
问题5:请简单描述一下享元模式和单例模式的区别?
答案5:享元模式和单例模式都是设计模式中比较常见的模式,但是它们的目的和使用场景不同。
享元模式的目的是通过共享对象来减少系统中对象的数量,从而降低系统的内存占用和运行开销,适用于需要大量创建相似对象的场景。而单例模式的目的是保证一个类只有一个实例,适用于需要全局访问一个唯一的对象的场景。
此外,享元模式和单例模式的实现方式也有一些不同。享元模式通常需要设计一个享元工厂类来管理对象池和对象的创建和获取,而单例模式通常使用静态方法或全局变量来保证只有一个实例。
问题6:请举例说明享元模式的应用?
答案6:享元模式可以应用于以下场景:
- 用于实现字体、颜色等的共享。
- 用于实现线程池、连接池等的对象池。
- 用于实现大型网站中的页面缓存,将页面中的公共部分缓存为共享对象,减少页面的加载时间和网络带宽的占用。
问题7:请问你在实际项目中有使用过享元模式吗?如果有,请简单描述一下你的使用场景和实现方式?
答案7:在我的一个项目中,我们需要实现一个图形化界面,其中包含大量的按钮和标签等控件。由于控件数量较多,我们考虑使用享元模式来共享相同类型的控件对象,从而降低系统内存占用和运行开销。
我们定义了一个控件类和一个控件工厂类。在控件工厂类中,我们维护了一个对象池,用于缓存已经创建的控件对象。当客户端需要使用一个控件时,我们先在对象池中查找是否存在相同类型的控件对象,如果存在,则直接返回该对象;否则,创建一个新的控件对象,并将其添加到对象池中。
通过使用享元模式,我们成功地减少了系统内存占用和运行开销,并提高了系统的性能和响应速度。
总的来说,享元模式通过共享对象来降低系统内存占用和运行开销,特别适用于需要大量创建相似对象的场景。在实现时,需要将对象的内部状态和外部状态分离,将共享内部状态的对象设计成享元,提供一个工厂类来创建和管理对象,并在使用时传入外部状态。