過濾器模式(C++實現)之幫你選個男朋友

過濾器模式(Filter Pattern)

過濾器模式(Filter Pattern)或標準模式(Criteria Pattern)是一種設計模式,這種模式允許開發人員使用不同的標準來過濾一組對象,通過邏輯運算以解耦的方式把它們連接起來。這種類型的設計模式屬於結構型模式,它結合多個標準來獲得單一標準。這種這麼官方的介紹當然是我從菜鳥教程複製過來的——過濾器模式|菜鳥教程
那就再談一談我自己的見解吧,感覺那些購物app(比如說淘寶)的篩選功能應該就是過濾器模式的教科書級實現吧。你可以篩選價格、風格、產地等等,這不就是一個個過濾器的實現嗎?!然後再加上組合過濾器的實現,哇,篩選功能出來了誒

UML圖

在這裏插入圖片描述
creiteria是所有過濾器的基類,與組合過濾器的關係應該算是聚合吧
至於boy,當然就是你的對象啊,狗頭.jpg

代碼實現

boy.h

#ifndef _BOY_
#define _BOY_

#include <string>
#include <iostream>
#include "stdio.h"

using namespace std;

class boy
{
private:
    string m_name;
    double m_weight;
    double m_height;
    string m_appearance;

public:
    boy(string name, double weight, double height, string appearance)
    {
        m_name = name;
        m_weight = weight;
        m_height = height;
        m_appearance = appearance;
    }
    bool operator < (const boy& b)
    {
        return this->m_name < b.get_name();
    }
    bool operator == (const boy& b)
    {
        return this->m_name == b.get_name();
    }
    string get_appearance()
    {
        return this->m_appearance;
    }
    double get_weight()
    {
        return this->m_weight;
    }
    double get_height()
    {
        return this->m_height;
    }
    string get_name() const
    {
        return this->m_name;
    }
    string show_me()
    {
        char describation[128] = {0};
        snprintf(describation, sizeof(describation) - 1,
                "name:%s\n%.2lfcm\n%.2lfkg\nappreance:%s\n", m_name.c_str(), m_height,
                m_weight, m_appearance.c_str());
        return describation;
    }
};
#endif

criteria.h

#ifndef _CRITERIA_
#define _CRITERIA_

#include "boy.h"
#include <string>
#include <list>
#include <iostream>
#include <math.h>
#include <algorithm>

using namespace std;

const double g_d_value = 1e-6;

class criteria
{
public:
    virtual list<boy> filter(list<boy> filter_list) = 0;
};

class criteria_handsome:public criteria
{
private:
    list<boy> m_list;

public:
    virtual list<boy> filter(list<boy> filter_list)
    {
        m_list.clear();
        list<boy>::iterator it;
        for (it = filter_list.begin(); it != filter_list.end(); it++)
        {
            if (it->get_appearance() == "handsome")
            {
                m_list.push_back(*it);
            }
        }
        return this->m_list;
    }
};

class criteria_higher:public criteria
{
private:
    list<boy> m_list;
    double m_lowest_height;

public:
    criteria_higher(double lowest_height)
    {
        m_lowest_height = lowest_height;
    }
    virtual list<boy> filter(list<boy> filter_list)
    {
        m_list.clear();
        list<boy>::iterator it;
        for (it = filter_list.begin(); it != filter_list.end(); it++)
        {
            if (it->get_height() - m_lowest_height >= g_d_value)
            {
                m_list.push_back(*it);
            }
        }
        return this->m_list;
    }
};

class or_criteria
{
private:
    list<boy> m_list;
    list<shared_ptr<criteria>> m_criteria_list;

public:
    list<boy> filter(list<boy> filter_list)
    {
        m_list.clear();
        list<shared_ptr<criteria>>::iterator it;
        for (it = m_criteria_list.begin(); it != m_criteria_list.end(); it++)
        {
            m_list.merge((*it)->filter(filter_list));
        }
        //||過濾器會累積重複的對象,去重
        m_list.sort();
        //unique指向不重複序列的下一個對象
        m_list.erase(unique(m_list.begin(), m_list.end()), m_list.end());
        return m_list;
    }
    void add_criteria(shared_ptr<criteria> filter)
    {
        if (filter == NULL)
            return;
        m_criteria_list.push_back(filter);
        return;
    }
};

class and_criteria
{
private:
    list<boy> m_list;
    list<shared_ptr<criteria>> m_criteria_list;

public:
    list<boy> filter(list<boy> filter_list)
    {
        m_list = filter_list;
        list<shared_ptr<criteria>>::iterator it;
        for (it = m_criteria_list.begin(); it != m_criteria_list.end(); it++)
        {
            m_list = (*it)->filter(m_list);
        }
        return m_list;
    }
    void add_criteria(shared_ptr<criteria> filter)
    {
        if (filter == NULL)
            return;
        m_criteria_list.push_back(filter);
        return;
    }
};
#endif
filter_pattern.cpp

#include <iostream>
#include <memory>
#include "criteria.h"
#include "boy.h"

using namespace std;

int main(int argc, const char *argv[])
{
    boy wyf("wyf", 85, 187.5, "handsome");
    boy lh("lh", 65.3, 175.5, "handsome");
    boy answer("answer", 75, 183, "handsome");
    boy your_boy_friend("xxx", 100, 180, "ugly");
    list<boy> list_boy;
    list_boy.push_back(wyf);
    list_boy.push_back(lh);
    list_boy.push_back(answer);
    list_boy.push_back(your_boy_friend);

    //單一過濾器
    shared_ptr<criteria> height_filter(new criteria_higher(178));
    list<boy> height_filter_boy = height_filter->filter(list_boy);
    list<boy>::iterator it;
    cout << "the list boy after height filter:" << endl;
    for (it = height_filter_boy.begin(); it != height_filter_boy.end(); it++)
    {
        cout << it->show_me() << endl;
    }

    //&&過濾器
    shared_ptr<criteria> face_filter(new criteria_handsome);
    and_criteria and_filter;
    and_filter.add_criteria(height_filter);
    and_filter.add_criteria(face_filter);

    list<boy> and_filter_boy = and_filter.filter(list_boy);
    cout << "the list boy after and filter:" << endl;
    for (it = and_filter_boy.begin(); it != and_filter_boy.end(); it++)
    {
        cout << it->show_me() << endl;
    }

    //||過濾器
    or_criteria or_filter;
    or_filter.add_criteria(height_filter);
    or_filter.add_criteria(face_filter);
    list<boy> or_filter_boy = or_filter.filter(list_boy);
    cout << "the list boy after or filter:" << endl;
    for (it = or_filter_boy.begin(); it != or_filter_boy.end(); it++)
    {
        cout << it->show_me() << endl;
    }
    return 0;
}

在寫demo的時候試了下C++智能指針和list容器中的元素是智能指針share_ptr,推薦使用7.3版本的gcc,體驗最新版的C++

結果

[root@bogon filter_pattern]# g++ filter_pattern.cpp 
[root@bogon filter_pattern]# ./a.out
the list boy after height filter:
name:wyf
187.50cm
85.00kg
appreance:handsome

name:answer
183.00cm
75.00kg
appreance:handsome

name:xxx
180.00cm
100.00kg
appreance:ugly

the list boy after and filter:
name:wyf
187.50cm
85.00kg
appreance:handsome

name:answer
183.00cm
75.00kg
appreance:handsome

the list boy after or filter:
name:answer
183.00cm
75.00kg
appreance:handsome

name:lh
175.50cm
65.30kg
appreance:handsome

name:wyf
187.50cm
85.00kg
appreance:handsome

name:xxx
180.00cm
100.00kg
appreance:ugly


過濾了下,最醜的當然是你的對象啊,狗頭.jpg

寫demo過程中碰見的幾個問題

  1. 組合過濾器,||過濾器,多次過濾一組對象,會得到重複的對象誒,怎麼搞?

那就把鏈表中的對象去重下吧,使用unique函數iterator unique(iterator it_1,iterator it_2,bool MyFunc);,注意該函數的頭文件#include <algorithm>,unique的實現是將鏈表中所有相鄰並且相同的元素往後移,所以使用unique前先list.sort,然後再配合list.erase使用就好。

  1. list容器的元素是自定義對象,編譯過程中容易遇到下面的問題:

在這裏插入圖片描述
這是編譯器不知道怎麼比較你寫的自定義對象了,所以你的自定義類中需要對一些==等符號去重載實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章