第31章 新的设计模式

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

第31章 新的设计模式的相关文章

第31章 新的设计模式(2)

31.2 对象池模式 31.2.1 定义和类图 (1)定义:对象池是一种设计模式,它通过管理有限对象复用来共享某些稀少或必须付出昂贵代价的资源. (2)类图: 31.2.2 对象池的扩展接口 (1)两级对象池方式:空闲对象池和已用对象池 (2)利用Wrapper模式包装复用对象,使附加一些属性(如空闲时间) class wrapper { private: int useTime; //开始使用时间 int unuseTime; //开始空闲时间 //其他附加属性 Object* reusabl

第31章 项目实战-PC端固定布局6

第31 章项目实战-PC 端固定布局[6]学习要点:1.分离CSS2.头部区域3.内容区域 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.分离CSS本节课,我们将要创建一个新的页面:旅游资讯.那么,现在需要解决的问题是,如果把首页重复的部分移植到新的页面而减少冗余.最恰当的方法就是:将CSS 部分中重复的部分分离出来,单独创建一个CSS,以便后续的页面重复调用.而首页的HTML 重复的部分,一般是通过动态网页,比如PHP 等解决重复问

1124: 零起点学算法31——开始新的起程

1124: 零起点学算法31--开始新的起程 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 2861  Accepted: 1381[Submit][Status][Web Board] Description 很开心大家学到现在. 从今天开始大家要有一个新的起程. 我们开始接触循环了! 你能让计算机计算1+2+3+...+10吗? 你能让计算机计算1+2+3+.._100吗? 只要告诉计算机,你

第31章 项目实战-PC端固定布局8

第31 章项目实战-PC 端固定布局[8]学习要点:1.归类合并2.子导航 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.归类合并在前面几节课中,有一部分HTML 代码比较松散,没有统一到一个类别块里.比如:很多的标签超链接没有归类到UL 里,导致一些问题等.//松散的<a>标签<a href="###">曼谷(12)</a><a href="###">东京

第31章 项目实战-PC端固定布局7

第31 章项目实战-PC 端固定布局[7]学习要点:1.侧栏制作2.详细代码 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.侧栏制作本节课,主要设计一下内容页面的侧栏部分,分三个小块.经过思考,侧栏会包含一些图片,而主要部分也会包含图片,那么侧栏放在左边可能会和主栏的图片冲突导致不协调,所以,我们把侧栏更换到右边.//实际上,还去掉了高度,让其自适应#container {width: 1263px;margin: 30px auto

第31章 项目实战-PC端固定布局3

第31 章项目实战-PC 端固定布局[3]学习要点:1.搜索区2.插入大图3.搜索框 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.搜索区本节课,我们接着header 头部往下,来设计一块搜索区.这个区域,可以是广告大图,也可以是用户注册,也可以是一个搜索条,都是一个大幅背景,内嵌一个表单.具体造型如下:从表面上来分析,就是插入一张背景大图,然后居中一个搜索条.但是,我们要求最小在1280 分辨率.最大在1920 分辨率能保持最佳的观

第31章 项目实战-PC端固定布局5

第31 章项目实战-PC 端固定布局[5]学习要点:1.底部区域2.说明区域3.版权及证件区 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.底部区域本节课,我们将探讨一下首页中最底部的区域.这部分区域由两个部分组成,一个是说明内容,有:合作伙伴.旅游FAQ 和联系方式,还有一个就是版权声明及各种手续证件编号.//底部区域父元素<footer id="footer">...</footer>//底部父元

第31章 项目实战-PC端固定布局4

第31 章项目实战-PC 端固定布局[4]学习要点:1.热门旅游区2.标题介绍区3.旅游项目区 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.热门旅游区本节课,我们将探讨一下首页最核心的部分,旅游区.这块内容由两个部分组成,一个是大标题,表示热门旅游区域.其次就是旅游项目的图片展示区域.具体如下://热门旅游区父元素<div id="tour">...</div>//旅游父元素#tour {width

第31 章项目实战-PC 端固定布局10

第31 章项目实战-PC 端固定布局[10]学习要点:1.机票预定2.代码详解 本章主要开始使用学习用HTML5 和CSS3 来构建Web 页面,第一个项目采用PC 端固定布局来实现.一.机票预定机票预定页面,具体如下:二.代码详解//全部代码<form action="###"><h2>机票预定</h2><div class="type"><p>航程类型<mark>单程</mark>