zoukankan      html  css  js  c++  java
  • 第31章 新的设计模式(1)

    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 + "	年龄:" + 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 + "	年龄:" + oss.str();
            return ret;
        }
    };
    View Code

    //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)规格模式中有个很严重的问题就是父类依赖子类,这种情景只有在非常明确不会发生变化的场景中存在,它不具备扩展性,是一种固化而不可变化的结构。一般面向对象设计中应该尽量避免。

  • 相关阅读:
    stark
    MySQL与JDBC
    存储过程/视图/触发器
    MyCat部署运行(Windows环境)与使用步骤详解
    常用单词总结
    表单校验---validation检验
    jQuery简介
    javascript简单介绍
    HTML&&CSS
    消息队列Java的简单实现
  • 原文地址:https://www.cnblogs.com/5iedu/p/5693374.html
Copyright © 2011-2022 走看看