主要解决
在有大量相似对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
优点
大大减少对象的创建,降低系统的内存,使效率提高。
缺点
提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱
关键代码
- Flyweight(享元):定义一个接口,通过它可以接收并作用于外部状态;
- Concrete Flyweight(具体享元):实现Flyweight接口,并为内部状态增加存储空间;
- Unshared Concrete Flyweight(非共享具体享元):由于客户端需要,享元对象不能进行共享的子类;
- Flyweight Factory(享元工厂):用于创建和管理Flyweight对象,可以通过享元工厂实现对象池。
示例
我们再以数据库连接为例,来进一步说明享元模式的使用场景。
假设我们正在编写一个数据库应用程序,其中有许多不同的数据库连接对象。在此过程中,由于每个连接都需要打开和关闭,并且提供的服务通常只需要少量的属性(如主机名、用户名和密码等),因此我们可以使用享元模式来共享这些属性,从而达到优化性能的目的。
首先,我们定义一个抽象的Database类作为所有数据库连接对象的基类,并在其中定义共同的属性和方法(如打开连接和关闭连接等)。然后,通过实现Database接口,我们可以创建多个ConcreteDatabase类(例如MySQL和Oracle),并为内部状态增加存储空间。
class Database {
public:
virtual void open() = 0;
virtual void close() = 0;
protected:
string host_;
string username_;
string password_;
};
class MySQL : public Database {
public:
MySQL(string host, string username, string password) {
this->host_ = host;
this->username_ = username;
this->password_ = password;
}
void open() override {
cout << "Open a MySQL database connection at " << this->host_
<< " with username " << this->username_ << endl;
}
void close() override {
cout << "Close the MySQL database connection at " << this->host_ << endl;
}
};
class Oracle : public Database {
public:
Oracle(string host, string username, string password) {
this->host_ = host;
this->username_ = username;
this->password_ = password;
}
void open() override {
cout << "Open an Oracle database connection at " << this->host_
<< " with username " << this->username_ << endl;
}
void close() override {
cout << "Close the Oracle database connection at " << this->host_ << endl;
}
};
接下来我们再定义一个DatabaseFactory类来实现享元工厂,以便创建和管理不同的Database对象,其中,DatabaseFactory的内部存储了一个SharePool对象,用于存放所有的共享Database对象,并通过getConnection方法对所有请求进行处理。如果请求对象已存在,直接返回共享对象;否则,创建新的对象并将其加入到SharePool中进行管理。
class SharePool {
public:
static shared_ptr<Database> getConnection(string host, string username, string password) {
auto key = host + username + password;
auto it = dbMap_.find(key);
if (it != dbMap_.end())
return it->second;
auto shareDb = make_shared<MySQL>(host, username, password);
dbMap_[key] = shareDb;
return shareDb;
}
static void clear() {
dbMap_.clear();
}
private:
static map<string, shared_ptr<Database>> dbMap_;
};
map<string, shared_ptr<Database>> SharePool::dbMap_;
class DatabaseFactory {
public:
static shared_ptr<Database> getConnection(string host, string username, string password) {
return SharePool::getConnection(host, username, password);
}
};
最后,在客户端中,我们可以通过DatabaseFactory来获取具体的MySQL或Oracle等数据库连接对象,并将共同的属性作为参数传入。
int main() {
auto conn1 = DatabaseFactory::getConnection("localhost", "root", "pwd");
conn1->open();
//do some work...
conn1->close();
auto conn2 = DatabaseFactory::getConnection("localhost", "root", "pwd");
conn2->open();
//do some work...
conn2->close();
// conn2与conn1是同一个对象
return 0;
}
参考
https://blog.csdn.net/u012011079/article/details/126033261
https://pythonjishu.com/yuqelkqbsifbaza/
https://www.runoob.com/design-pattern/flyweight-pattern.html