过滤器模式(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过程中碰见的几个问题
- 组合过滤器,||过滤器,多次过滤一组对象,会得到重复的对象诶,怎么搞?
那就把链表中的对象去重下吧,使用unique函数iterator unique(iterator it_1,iterator it_2,bool MyFunc);
,注意该函数的头文件#include <algorithm>
,unique的实现是将链表中所有相邻并且相同的元素往后移,所以使用unique前先list.sort,然后再配合list.erase使用就好。
- list容器的元素是自定义对象,编译过程中容易遇到下面的问题:
这是编译器不知道怎么比较你写的自定义对象了,所以你的自定义类中需要对一些==等符号去重载实现。