c/c++设计模式---享元模式
引入享元模式:
围棋游戏:
namespace _nmsp1 { enum EnumColor //棋子类型 { Black, //黑 White //白 }; struct Position //棋子位置 { int m_x; int m_y; Position(int tmpx, int tmpy) :m_x(tmpx), m_y(tmpy) {} //构造函数 }; class Piece //棋子 { public: Piece(EnumColor tmpcolor, Position tmppos) :m_color(tmpcolor), m_pos(tmppos) {} //构造函数 void draw() //棋子的绘制 { if (m_color == Black) { cout << "在位置:(" << m_pos.m_x << "," << m_pos.m_y << ")处绘制了一个黑色棋子!" << endl; //....这里可以是一系列用于具体绘制的代码 } else { cout << "在位置:(" << m_pos.m_x << "," << m_pos.m_y << ")处绘制了一个白色棋子!" << endl; //....这里可以是一系列用于具体绘制的代码 } } private: EnumColor m_color; //棋子颜色 Position m_pos; //棋子位置 }; } int main() { std::list<_nmsp1::Piece*> piecelist; _nmsp1::Piece* p_piece1 = new _nmsp1::Piece(_nmsp1::Black, _nmsp1::Position(3, 3)); //黑色落子到3,3位置 p_piece1->draw(); _nmsp1::Piece* p_piece2 = new _nmsp1::Piece(_nmsp1::White, _nmsp1::Position(5, 5)); //白色落子到5,5位置 p_piece2->draw(); _nmsp1::Piece* p_piece3 = new _nmsp1::Piece(_nmsp1::Black, _nmsp1::Position(4, 6)); //黑色落子到4,6位置 p_piece3->draw(); _nmsp1::Piece* p_piece4 = new _nmsp1::Piece(_nmsp1::White, _nmsp1::Position(5, 7)); //白色落子到5,7位置 p_piece4->draw(); //..... piecelist.push_back(p_piece1); piecelist.push_back(p_piece2); piecelist.push_back(p_piece3); piecelist.push_back(p_piece4); //释放资源 delete p_piece1; delete p_piece2; delete p_piece3; delete p_piece4; }
享元模式实现:
namespace _nmsp2 { enum EnumColor //棋子类型 { Black, //黑 White //白 }; struct Position //棋子位置 { int m_x; int m_y; Position(int tmpx, int tmpy) :m_x(tmpx), m_y(tmpy) {} //构造函数 }; class Piece //棋子抽象类 { public: virtual ~Piece() {} //做父类时析构函数应该为虚函数 public: virtual void draw(Position tmppos) = 0; }; class BlackPiece :public Piece //黑色棋子 { public: //int ins; virtual void draw(Position tmppos) { cout << "在位置:(" << tmppos.m_x << "," << tmppos.m_y << ")处绘制了一个黑色棋子!" << endl; //....这里可以是一系列用于具体绘制的代码 } }; class WhitePiece :public Piece //白色棋子 { public: virtual void draw(Position tmppos) { cout << "在位置:(" << tmppos.m_x << "," << tmppos.m_y << ")处绘制了一个白色棋子!" << endl; //....这里可以是一系列用于具体绘制的代码 } }; class pieceFactory //创建棋子的工厂 { public: virtual ~pieceFactory() { //释放内存 for (auto iter = m_FlyWeightMap.begin(); iter != m_FlyWeightMap.end(); ++iter) { Piece* tmpfw = iter->second; delete tmpfw; } m_FlyWeightMap.clear(); //可有可无 } Piece* getFlyWeight(EnumColor tmpcolor) //获取享元对象,也就是获取被共享的棋子对象 { auto iter = m_FlyWeightMap.find(tmpcolor); if (iter == m_FlyWeightMap.end()) { //没有该享元对象,那么就创建出来 Piece* tmpfw = nullptr; if (tmpcolor == Black) //黑子 { tmpfw = new BlackPiece(); } else //白子 { tmpfw = new WhitePiece(); } m_FlyWeightMap.insert(make_pair(tmpcolor, tmpfw)); //以棋子颜色枚举值作为key,增加条目到map中 return tmpfw; } else { return iter->second; } } private: std::map<EnumColor, Piece*> m_FlyWeightMap; //享元池,用map容器来保存所有的享元对象,一共就两个享元对象(黑色棋子一个,白色棋子一个) }; } int main() { _nmsp2::pieceFactory* pfactory = new _nmsp2::pieceFactory(); _nmsp2::Piece* p_piece1 = pfactory->getFlyWeight(_nmsp2::Black); p_piece1->draw(_nmsp2::Position(3, 3)); //黑子落子到3,3位置 _nmsp2::Piece* p_piece2 = pfactory->getFlyWeight(_nmsp2::White); p_piece2->draw(_nmsp2::Position(5, 5)); //白子落子到5,5位置 _nmsp2::Piece* p_piece3 = pfactory->getFlyWeight(_nmsp2::Black); p_piece3->draw(_nmsp2::Position(4, 6)); //黑子落子到4,6位置 _nmsp2::Piece* p_piece4 = pfactory->getFlyWeight(_nmsp2::White); p_piece4->draw(_nmsp2::Position(5, 7)); //白子落子到5,7位置 //释放资源 delete pfactory; return 0; }
享元(Flyweight)模式:蝇量模式,结构型模式,解决的是面向对象程序设计的性能问题
//享元:被共享的单元或者被共享的对象。Flyweight——轻量级(占用的内存更少)。
//设计思想:当需要某个对象时,尽量共用已经创建出的同类对象从而避免频繁使用new创建同类或者相似的对象。
//(1)从一个典型的范例开始
//享元对象(被共享的对象):黑棋,白棋
//(2)引入享元(Flyweight)模式
//该模式避免了程序中出现大量相同或者相似的对象,通过共享对象的方式实现相似对象的重用。
//定义:运用共享技术有效地支持大量细粒度的对象(的复用)。
//内部状态:存储在享元对象内部,一直不会发生改变的状态。这种状态可以被共享。
//外部状态:随着外部环境和各种动作因素的改变而发生改变的状态,这种状态不可以被共享。
//
//享元模式的目的:减少对象数量,节省内存,提高程序运行效率。
//三种角色:
//a)Flyweight(抽象享元类):Piece类
//b)ConcreteFlyweight(具体享元类):BlackPiece、WhitePiece。
//c)FlyWeightFactory(享元工厂类):pieceFactory
//使用情形:
//a)程序中有大量相同或者相似对象造成内存大量消耗。
//b)对象的大部分状态都是或者都可以转变成外部状态,通过参数传入到对象中。
//c)享元池的引入增加了程序实现的复杂性,当然也有一定内存开销,使用享元模式要衡量性价比。
//不要将享元模式 对象池,连接池,线程池等混为一谈。
享元模式是一种结构型设计模式,旨在减少应用程序中相似对象的内存使用或计算成本,通过共享相同状态的对象实例来达到节省资源的目的。在享元模式中,共享的对象被称为“享元”,而对于不同的上下文或情境,可以通过在享元对象中维护外部状态来实现个性化。
这个模式的关键思想是将对象的状态分为内部状态和外部状态。内部状态是对象共享的部分,存储在享元对象内部;而外部状态是对象可变的部分,需要在运行时由客户端传递给享元对象。通过这种方式,可以在不同的上下文中重用相同的享元对象,从而节省内存和提高性能。
享元模式通常与工厂模式结合使用,以便动态创建和管理享元对象。这种模式在需要大量相似对象时特别有用,例如图形编辑器中的图形对象,游戏中的粒子效果,或者操作系统中的字体对象。
下面是一个简单的 C++ 代码示例,演示了如何使用享元模式来共享相同状态的对象实例:
#include <iostream>
#include <unordered_map>
// 享元对象类
class Flyweight {
public:
virtual void operation(int extrinsicState) = 0;
};
// 具体享元对象类
class ConcreteFlyweight : public Flyweight {
public:
void operation(int extrinsicState) override {
std::cout << "具体享元对象操作,外部状态:" << extrinsicState << std::endl;
}
};
// 享元工厂类
class FlyweightFactory {
private:
std::unordered_map<std::string, Flyweight*> flyweights;
public:
Flyweight* getFlyweight(std::string key) {
if (flyweights.find(key) == flyweights.end()) {
flyweights[key] = new ConcreteFlyweight();
}
return flyweights[key];
}
};
int main() {
FlyweightFactory factory;
Flyweight* fw1 = factory.getFlyweight("key1");
fw1->operation(1);
Flyweight* fw2 = factory.getFlyweight("key2");
fw2->operation(2);
Flyweight* fw3 = factory.getFlyweight("key1");
fw3->operation(3); // 复用了fw1对应的享元对象
return 0;
}
在这个例子中,ConcreteFlyweight
是具体的享元对象类,实现了 Flyweight
接口。FlyweightFactory
是享元工厂类,负责创建和管理享元对象。在 main
函数中,演示了如何通过享元工厂获取共享的享元对象,并传递外部状态进行操作。由于重复使用了相同的 key,可以看到第一个和第三个操作使用了同一个享元对象。
这里只是一个简单的示例,实际应用中可能会更复杂,需要根据具体情况来设计和实现享元模式。