31.1 规格模式(Specification 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; } };