31.1 规格模式(Specitification Pattern)
31.1.1 查询筛选条件
(1)场景:根据条件从数据库的用户表中筛选出对象
(2)存在问题
①findUserByAgeThan和findUserByName两个方法中除了if后面的判断条件不同,其他地方完全一样
②这两个程序中唯一的变化点就是条件语句,可以将这里封装起来,后面的例子会设计一个规格类,用于封装整个条件语句。
【编程实验】根据条件筛选用户表数据
//新设计模式——规格模式 //实例:实现不同条件的查询(不使用规格模式) //存在问题: //1. findUserByAgeThan和findUserByName两个方法中除了if后面的判断条件 //不同,其他地方完全一样 //2. 这两个程序中唯一的变化点就是条件语句,可以将这里封装起来,后面的 // 例子会设计一个规格类,用于封装整个条件语句 #include <iostream> #include <string> #include <vector> #include <sstream> using namespace std; //用户类 class User { private: string name; //姓名 int age; //年龄 public: User(string name, int age) { this->name = name; this->age = age; } string getName(){return name;} void setName(string value){name = value;} int getAge(){return age;} void setAge(int value){age = value;} string toString() { ostringstream oss; oss << age; string ret = "用户名:" + name + "\t年龄:" + oss.str(); return ret; } }; //用户操作对象接口 class IUserProvider { public: virtual vector<User*>* findUserByName(string name) = 0; virtual vector<User*>* findUserByAgeThan(int age) = 0; }; //用户操作类 class UserProvider : public IUserProvider { private: vector<User*>* userList; public: UserProvider(vector<User*>* userList) { this->userList = userList; } //年龄大于指定年龄 vector<User*>* findUserByAgeThan(int age) { vector<User*>* ul = new vector<User*>(); vector<User*>::iterator iter = userList->begin(); for(;iter != userList->end(); ++iter) { if((*iter)->getAge() > age) //与findUserByName唯一的不同 { ul->push_back((*iter)); } } return ul; } //姓名等于指定姓名的用户 vector<User*>* findUserByName(string name) { vector<User*>* ul = new vector<User*>(); vector<User*>::iterator iter = userList->begin(); for(;iter != userList->end(); ++iter) { if((*iter)->getName() == name) //与findUserByAgeThan唯一的不同 { ul->push_back((*iter)); } } return ul; } }; void createUsers(vector<User*>& userList) { userList.push_back( new User("苏三",3) ); userList.push_back( new User("牛二",8) ); userList.push_back( new User("张三",10) ); userList.push_back( new User("李四",15) ); userList.push_back( new User("王五",18) ); userList.push_back( new User("赵六",20) ); userList.push_back( new User("马七",25) ); userList.push_back( new User("杨八",30) ); userList.push_back( new User("侯九",35) ); userList.push_back( new User("布十",40) ); } void delUsers(vector<User*>& userList) { vector<User*>::iterator iter = userList.begin(); while (iter != userList.end()) { delete (*iter); ++iter; } userList.clear(); } void showUsers(vector<User*>& userList) { vector<User*>::iterator iter = userList.begin(); while (iter != userList.end()) { cout << (*iter)->toString() <<endl; ++iter; } } int main() { //首先初始化一批用户 vector<User*> userList; createUsers(userList); //定义一个用户查询类 IUserProvider* userProvider = new UserProvider(&userList); //查询并打印年龄大于20岁的用户 vector<User*>* ul = userProvider->findUserByAgeThan(20); showUsers(*ul); ul->clear(); delete ul; delUsers(userList); return 0; }; /*输出结果: 用户名:马七 年龄:25 用户名:杨八 年龄:30 用户名:侯九 年龄:35 用户名:布十 年龄:40 */
31.1.2 解决方案
(1)规格模式
(2)类图
①规格书接口中增加了与或非操作,返回值为规格书类型这样设计的目的是为了连续调用。
②由于与或非是不可扩展的操作,这部分是不可能发生变化的部分。因此,这里出现了父类对子类的依赖,这种情况只有在非常明确不会发生变化的场景中。
【编程实验】
//User.h
#pragma once #include <string> #include <sstream> using namespace std; //************************************************辅助类***************************************** //用户类 class User { private: string name; //姓名 int age; //年龄 public: User(string name, int age) { this->name = name; this->age = age; } string getName(){return name;} void setName(string value){name = value;} int getAge(){return age;} void setAge(int value){age = value;} string toString() { ostringstream oss; oss << age; string ret = "用户名:" + name + "\t年龄:" + oss.str(); return ret; } };
//Specification.h
#pragma once #include "User.h" //**************************************定义规格接口***************************** //规格书接口(支持与或非) class ISpecification { public: //候选者是否满足要求 virtual bool isSatisfiedBy(User* user) = 0; //and操作 virtual ISpecification* andOp(ISpecification* spec) = 0; //or操作 virtual ISpecification* orOp(ISpecification* spec) = 0; //not操作 virtual ISpecification* notOp() = 0; virtual ~ISpecification(){} }; //组合规格书 class CompositeSpecification : public ISpecification { public: ISpecification* andOp(ISpecification* spec); ISpecification* orOp(ISpecification* spec); ISpecification* notOp(); }; //and操作 class AndSpecification : public CompositeSpecification { private: ISpecification* left; ISpecification* right; public: AndSpecification(ISpecification* left, ISpecification* right); //进行and运算 bool isSatisfiedBy(User* user); }; //and操作 class OrSpecification : public CompositeSpecification { private: ISpecification* left; ISpecification* right; public: OrSpecification(ISpecification* left, ISpecification* right); //进行or运算 bool isSatisfiedBy(User* user); }; //not操作 class NotSpecification : public CompositeSpecification { private: ISpecification* spec; public: NotSpecification(ISpecification* spec); //进行not运算 bool isSatisfiedBy(User* user); }; //姓名相同的规格书 class UserByNameEqual : public CompositeSpecification { private: string name; //姓名 public: UserByNameEqual(string name); //检验用户是否满足条件 bool isSatisfiedBy(User* user); }; //年龄大于20岁的规格书 class UserByAgeThan : public CompositeSpecification { private: int age; //年龄 public: UserByAgeThan(int age); //检验用户是否满足条件 bool isSatisfiedBy(User* user); }; //like规格书 class UserNameLike: public CompositeSpecification { private: string name; //姓名 public: UserNameLike(string name); //检验用户是否满足条件 bool isSatisfiedBy(User* user); };
//Specification.cpp
#include "Specification.h" //****************************CompositeSpecification类*********************** //and操作 ISpecification* CompositeSpecification::andOp(ISpecification* spec) { return new AndSpecification(this, spec); }; //or操作 ISpecification* CompositeSpecification::orOp(ISpecification* spec) { return new OrSpecification(this, spec); }; //not操作 ISpecification* CompositeSpecification::notOp() { return new NotSpecification(this); }; //****************************AndSpecification*********************** //and操作 AndSpecification::AndSpecification(ISpecification* left, ISpecification* right) { this->left = left; this->right = right; } //进行and运算 bool AndSpecification::isSatisfiedBy(User* user) { return left->isSatisfiedBy(user) && right->isSatisfiedBy(user); } //****************************OrSpecification*********************** //and操作 OrSpecification::OrSpecification(ISpecification* left, ISpecification* right) { this->left = left; this->right = right; } //进行or运算 bool OrSpecification::isSatisfiedBy(User* user) { return left->isSatisfiedBy(user) || right->isSatisfiedBy(user); } //****************************OrSpecification*********************** //not操作 NotSpecification::NotSpecification(ISpecification* spec) { this->spec = spec; } //进行not运算 bool NotSpecification::isSatisfiedBy(User* user) { return ! spec->isSatisfiedBy(user); } //****************************UserByNameEqual*********************** //姓名相同的规格书 UserByNameEqual::UserByNameEqual(string name) { this->name = name; } //检验用户是否满足条件 bool UserByNameEqual::isSatisfiedBy(User* user) { return (user->getName() == name); } //****************************UserByNameEqual*********************** //年龄大于20岁的规格书 UserByAgeThan::UserByAgeThan(int age) { this->age = age; } //检验用户是否满足条件 bool UserByAgeThan::isSatisfiedBy(User* user) { return (user->getAge() >= age); } //****************************UserNameLike*********************** //like规格书 UserNameLike::UserNameLike(string name) { this->name = name; } //检验用户是否满足条件 bool UserNameLike::isSatisfiedBy(User* user) { int nPos = (user->getName()).find(name); return (nPos >=0); }
//main.cpp
//新设计模式——规格模式 //实例:实现不同条件的查询(使用规格模式) //说明: 本例除了可以进行简单条件语句的查询,也可以复合语 // 包含与、或、非等 #include <iostream> #include <string> #include <vector> #include "Specification.h" #include "User.h" using namespace std; //用户操作对象接口 class IUserProvider { public: virtual vector<User*>* findUser(ISpecification* spec) = 0; virtual ~IUserProvider(){} }; //用户操作类 class UserProvider : public IUserProvider { private: vector<User*>* userList; public: UserProvider(vector<User*>* userList) { this->userList = userList; } //查询指定规格的用户 vector<User*>* findUser(ISpecification* spec) { vector<User*>* ul = new vector<User*>(); vector<User*>::iterator iter = userList->begin(); for(;iter != userList->end(); ++iter) { if(spec->isSatisfiedBy(*iter)) //注意,条件语句被规格书所替代 { ul->push_back((*iter)); } } return ul; } }; //**********************************************辅助函数*********************************** void createUsers(vector<User*>& userList) { userList.push_back( new User("苏三",3) ); userList.push_back( new User("牛二",8) ); userList.push_back( new User("张三",10) ); userList.push_back( new User("李四",15) ); userList.push_back( new User("王五",18) ); userList.push_back( new User("赵六",20) ); userList.push_back( new User("马七",25) ); userList.push_back( new User("杨八",30) ); userList.push_back( new User("侯九",35) ); userList.push_back( new User("布十",40) ); userList.push_back( new User("苏国庆",23) ); userList.push_back( new User("国庆牛",82) ); userList.push_back( new User("张国庆三",10) ); } void delUsers(vector<User*>& userList) { vector<User*>::iterator iter = userList.begin(); while (iter != userList.end()) { delete (*iter); ++iter; } userList.clear(); } void showUsers(vector<User*>& userList) { vector<User*>::iterator iter = userList.begin(); while (iter != userList.end()) { cout << (*iter)->toString() <<endl; ++iter; } } int main() { //首先初始化一批用户 vector<User*> userList; createUsers(userList); //定义一个用户查询类 IUserProvider* userProvider = new UserProvider(&userList); //查询并打印年龄大于20岁的用户 ISpecification* spec1 = new UserByAgeThan(20); ISpecification* spec2 = new UserNameLike("国庆"); ISpecification* spec3 = spec1->andOp(spec2); vector<User*>* ul = userProvider->findUser(spec3); showUsers(*ul); ul->clear(); delete spec1; delete spec2; delete spec3; delete ul; delete userProvider; delUsers(userList); return 0; }; /*输出结果: 用户名:苏国庆 年龄:23 用户名:国庆牛 年龄:82 */
31.1.3 小结
(1)基类代表所有规格书,它的目的是描述一个完整的、可组合的规格书,它代表的是一个整体,其下的And、Or、Not规格书、年龄大于基准年龄等规格书是一个个真实的实现,也就是一个局部,这是组合模式的一种特殊应用。
(2)每个规格书又是一个个策略,它完成一系列逻辑的封装,这些策略可以相互替换。
(3)规格模式可巧妙实现对象筛选功能。在类似于多个对象中筛选查找,或者业务规则不适于放在任何己有实体或值对象中,而且规则变化和组合会掩盖那些领域对象的基本含义,可以考虑该模式
(4)规格模式中有个很严重的问题就是父类依赖子类,这种情景只有在非常明确不会发生变化的场景中存在,它不具备扩展性,是一种固化而不可变化的结构。一般面向对象设计中应该尽量避免。
时间: 2024-10-12 13:19:30