使用场景
(1)系统中存在大量的相似对象
(2)细粒度的对象都具有较接近的外部状态,而且内部状态与环境无关,也就是说对明没有特定的身份。
(3)需要缓冲池的场景
(4)如果不考虑对象的外部状态,可以用相对较少的共享对象取代很多组合对象,可以使用享元模式来共享对象,然后组合对象来使用这些共享对象。
【编程实验】权限管理系统
//声明文件
//****************************************************************************************** //结构型模式:享元模式 //场景:权限管理。 //几个概念 //1.安全实体:如某个数据表 //2.权限:指很对安全实体进行的操作,如查看、修改、删除等。 //几个问题 //1.因安全实体的权限可能被成千上万的人共享。如“人员列表”的查询权限 // 为了减少创建对象,可以将“人员列表”的“查询”权限作为一个享元对象,放入享元工厂 //2.为了增加实用性,这里采用享元模式+组合模式的方式实现了多层次的权限管理。 // 组合:将安全实体的权限进行组合,如“查看”+“修改” = “操作”权限,由于“操作”是组 // 合的权限,所以无须在享元工厂中缓存,即这个组合对象是个UnsharedConcreteFlyweight // 对象。 //3. 享元工厂的垃圾回收:创建一个线程,专门负责过期的垃圾回收 #include <iostream> #include <string> #include <vector> #include <map> #include <sstream> #include <ctime> #include <windows.h> #include <process.h> using namespace std; ////////////////////////////////////////////////////////////////////////// // 字符串分割 // // ------------------------------------------------------------------------- // 函数 : Split // 功能 : 分割STL标准字符串 // 返回值 : void // 参数 : Container<std::basic_string<CharT> >& v 存放分割结果 // 参数 : const std::basic_string<CharT>& s 待分割字符串 // 参数 : const std::basic_string<CharT>& c 分割字符串 // ------------------------------------------------------------------------- template<typename CharT, template<typename S, typename Q = std::allocator<S> > class Container> void Split(Container<std::basic_string<CharT> >& v, const std::basic_string<CharT>& s, const std::basic_string<CharT>& c); //*******************************************辅助类****************************** //测试数据(在内存中模拟数据库中的值) class CDataBase{ public: static vector<string> vecSingle;//用来存放单独授权数据的值 //其中的key为组合数据的id,value为该组合包含的多条授权数据的值 static map<string, vector<string>> mpMulti; //用来存放组合授权数据的值 }; //**********************************享元类************************ //享元接口:描述授权数据的接口 class CPermitWeight{ public: virtual ~CPermitWeight(); virtual bool Match(string SecurityEntity, string Permit) = 0; virtual void Add(CPermitWeight* pPermit) = 0; //享元模式与组合模式的结合。为Flyweight添加子Flyweight对象 virtual void Disp() = 0;//输出自身权限 virtual bool IsAdmin() = 0;//判断是不是组合权限 }; //具体享元对象(封装授权数据中重复出现的部分) //由于add是针对组合对象的,而这个可共享的是叶子对象,所以这里抛出 //异常就可以了。 //享元工厂里存放的是这个对象,如“薪资数据表的查看权限”。因为某一权限 //可能被分配给成上千万个人,所以需要缓存。即享元 class CSingleFly : public CPermitWeight{ private://内部状态 string strSecurityEntity;//安全实体 string strPermit; //权限 public: //构造函数,传入状态数据,包含安全实体和权限的数据,用“,”分隔 CSingleFly(string state); ~CSingleFly(); string GetSecurityEntity(); string GetPermit(); bool Match(string securityentity, string permit); void Add(CPermitWeight* pPermit); //叶子对象,什么都不做!这里也可以抛出异常! void Disp();//输出属性(成员变量即可) bool IsAdmin();//返回false表示是叶子节点 }; //不需要共享的享元对象的实现,也是组合模式中的组合对象 class CMultiFly : public CPermitWeight{ private: //记录每个组合对象所包含的子组件 vector<CPermitWeight*> vRight; public: ~CMultiFly(); void Add(CPermitWeight* permit); bool Match(string securityentity, string permit); void Disp();//输出每个叶子节点的权限 bool IsAdmin();//返回true表示是分支节点 }; //****************************************************************** //享元工厂 class CAdmin{ private: static map<string, CPermitWeight*> mpPermit; static multimap<string, CPermitWeight*> mpUser; public: static CPermitWeight* GetWeight(string key); //从数据库中获取某人所拥有的权限 static void DispAllPermit(); static void RemoveAllPermit(); static void DispAllUser(); static void RemoveAllUser(); static vector<CPermitWeight*> QueryPermitByUser(string user); //判断某用户对某个安全实体是否拥有某种权限 static bool HasPermit(string user, string securityentity, string permit); };
//实现文件
////////////////////////////////////////////////////////////////////////// // 字符串分割 // // ------------------------------------------------------------------------- // 函数 : Split // 功能 : 分割STL标准字符串 // 返回值 : void // 参数 : Container<std::basic_string<CharT> >& v 存放分割结果 // 参数 : const std::basic_string<CharT>& s 待分割字符串 // 参数 : const std::basic_string<CharT>& c 分割字符串 // ------------------------------------------------------------------------- template<template<typename S, typename Q = std::allocator<S> > class Container> void Split(Container<std::basic_string<char> >& v, const std::basic_string<char>& s, const std::basic_string<char>& c) { if (0 == c.length()) return; std::basic_string<char>::size_type pos1 = 0; std::basic_string<char>::size_type pos2 = 0; pos1 = 0; pos2 = s.find(c); while (std::basic_string<char>::npos != pos2){ v.push_back(s.substr(pos1, pos2 - pos1)); pos1 = pos2 + c.size(); pos2 = s.find(c, pos1); } if (pos1 != s.length()) { v.push_back(s.substr(pos1)); } } //*******************************************辅助类****************************** //测试数据(在内存中模拟数据库中的值) //单独授权数据 static vector<string>::value_type init_value1[] = { vector<string>::value_type("ZhangSan,PersonTable,Query,1"), vector<string>::value_type("LiSi,PersonTable,Query,1"), vector<string>::value_type("LiSi,OptSalaryTable,,2"), vector<string>::value_type("ZhangSan0,PersonTable,Query,1"), vector<string>::value_type("ZhangSan1,PersonTable,Query,1"), vector<string>::value_type("ZhangSan2,PersonTable,Query,1") }; vector<string> CDataBase::vecSingle(init_value1, init_value1+6); //组合授权数据 static vector<string>::value_type init_value2[] = { vector<string>::value_type("SalaryTable,Query"), vector<string>::value_type("SalaryTable,Modify") }; static vector<string> CompositePermit(init_value2, init_value2+2); static map<string, vector<string>>::value_type init_value3[] = { map<string, vector<string>>::value_type("OptSalaryTable", CompositePermit) }; map<string, vector<string>> CDataBase::mpMulti(init_value3, init_value3+1); //**********************************享元类************************ //享元接口:描述授权数据的接口 CPermitWeight::~CPermitWeight(){} //具体享元对象(封装授权数据中重复出现的部分) //由于add是针对组合对象的,而这个可共享的是叶子对象,所以这里抛出 //异常就可以了。 //享元工厂里存放的是这个对象,如“薪资数据表的查看权限”。因为某一权限 //可能被分配给成上千万个人,所以需要缓存。即享元 //构造函数,传入状态数据,包含安全实体和权限的数据,用“,”分隔 CSingleFly::CSingleFly(string state) { vector<string> vString; Split(vString, state, ","); strSecurityEntity = vString[0]; strPermit = vString[1]; } CSingleFly::~CSingleFly(){ cout << "~CSingleFly" << endl;} string CSingleFly::GetSecurityEntity(){return strSecurityEntity;} string CSingleFly::GetPermit(){return strPermit;} bool CSingleFly::Match(string securityentity, string permit) { return (strSecurityEntity == securityentity && strPermit == permit); } void CSingleFly::Add(CPermitWeight* pPermit){} void CSingleFly::Disp() { cout << strSecurityEntity << " : " << strPermit << endl; } bool CSingleFly::IsAdmin(){return false;} //不需要共享的享元对象的实现,也是组合模式中的组合对象 CMultiFly::~CMultiFly(){ cout << "~CMultiFly" << endl;} void CMultiFly::Add(CPermitWeight* permit){ vRight.push_back(permit);} bool CMultiFly::Match(string securityentity, string permit) { bool bMatched = false; for(vector<CPermitWeight*>::iterator it = vRight.begin(); it != vRight.end(); it++){ if((*it)->Match(securityentity, permit)){ bMatched = true; break; } } return bMatched; } void CMultiFly::Disp() { for(vector<CPermitWeight*>::iterator it = vRight.begin(); it != vRight.end(); it++){ CPermitWeight* pPermit = (*it); cout << pPermit << " : "; pPermit->Disp(); } } bool CMultiFly::IsAdmin(){return true;} //****************************************************************** //享元工厂 CPermitWeight* CAdmin::GetWeight(string key) { CPermitWeight* pPermit = mpPermit[key]; if(pPermit == NULL){ pPermit = new CSingleFly(key); mpPermit[key] = pPermit; } return pPermit; } //从数据库中获取某人所拥有的权限 void CAdmin::DispAllPermit(){ cout << "******************************************" << endl; for(map<string, CPermitWeight*>::iterator it = mpPermit.begin(); it != mpPermit.end(); it++){ cout << it->first << " : " << it->second << endl; } cout << "******************************************" << endl << endl; } void CAdmin::RemoveAllPermit(){ for(map<string, CPermitWeight*>::iterator it = mpPermit.begin(); it != mpPermit.end(); ){ cout << it->first << " : " << it->second << endl; CPermitWeight* pPermit = it->second; delete pPermit; it = mpPermit.erase(it); } } void CAdmin::DispAllUser(){ cout << "******************************************" << endl; for(multimap<string, CPermitWeight*>::iterator it = mpUser.begin(); it != mpUser.end(); it++){ cout << it->first << " : " << it->second << endl; CPermitWeight* pPermit = it->second; pPermit->Disp(); } cout << "******************************************" << endl << endl; } void CAdmin::RemoveAllUser(){ for(multimap<string, CPermitWeight*>::iterator it = mpUser.begin(); it != mpUser.end(); ){ CPermitWeight* pPermit = it->second; if(pPermit->IsAdmin()){ cout << it->first << " : " << it->second << endl; delete pPermit; } it = mpUser.erase(it); } } vector<CPermitWeight*> CAdmin::QueryPermitByUser(string user) { vector<CPermitWeight*> vPermit; vector<string> vString; for(vector<string>::iterator it = CDataBase::vecSingle.begin(); it != CDataBase::vecSingle.end(); it++){ vString.clear(); Split(vString, *it, ","); if(vString.size() < 4) break; if(vString[0] == user){ CPermitWeight* pPermit = NULL; if(vString[3] == "2"){ pPermit = new CMultiFly();//表示组合 cout << "UserName : " << user << "<<<<<<<<<<<<<<<<<<<<<<<<<" << endl; vector<string> vTmp = CDataBase::mpMulti[vString[1]]; for(vector<string>::iterator it = vTmp.begin(); it != vTmp.end(); it++){ pPermit->Add(CAdmin::GetWeight(*it)); } } else pPermit = CAdmin::GetWeight(vString[1] + "," + vString[2]); vPermit.push_back(pPermit); mpUser.insert(make_pair(user, pPermit)); } } return vPermit; } //判断某用户对某个安全实体是否拥有某种权限 bool CAdmin::HasPermit(string user, string securityentity, string permit){ bool bHas = false; vector<CPermitWeight*> vPermit = QueryPermitByUser(user); for(vector<CPermitWeight*>::iterator it = vPermit.begin(); it != vPermit.end(); it++){ if((*it)->Match(securityentity, permit)){ bHas = true; break; } } return bHas; } map<string, CPermitWeight*> CAdmin::mpPermit; multimap<string, CPermitWeight*> CAdmin::mpUser;
//测试客户端
void main() { cout << "ZhangSan Query PersonTable : " << CAdmin::HasPermit("ZhangSan", "PersonTable", "Query") << endl; cout << "LiSi Query SalaryTable : " << CAdmin::HasPermit("LiSi", "SalaryTable", "Query") << endl; cout << "LiSi Modify SalaryTable : " << CAdmin::HasPermit("LiSi", "SalaryTable", "Modify") << endl; cout << "ZhangSan0 Query SalayTable : " << CAdmin::HasPermit("ZhangSan0", "SalaryTable", "Query") << endl; cout << "ZhangSan1 Modify SalaryTable : " << CAdmin::HasPermit("ZhangSan1", "SalaryTable", "Modify") << endl; cout << "ZhangSan2 Query PersonTable : " << CAdmin::HasPermit("ZhangSan2", "PersonTable", "Query") << endl; CAdmin::DispAllPermit(); CAdmin::DispAllUser(); CAdmin::RemoveAllUser(); CAdmin::RemoveAllPermit(); }