Java计模模式之六 ----- 组合模式和过滤器模式
前言
在中我们学习了结构型模式的外观模式和装饰器模式。本篇则来学习下组合模式和过滤器模式。
组合模式
简介
组合模式是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
简单来说的话,就是根据树形结构把相似的对象进行组合,然后表示该部分是用来做啥的。在<大话设计模式>中有个很形象的例子,就是电脑中的 文件系统。
文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。
当然,这里我们也可以使用一个简单的示例来对组合模式进行讲解。
在学校中,有很多学生,但是这些学生中又有不同的身份,有的学生是学生会主席,有的是学生会委员,有的是班长,有的是体育委员等等, 当然大部分都是普通的学生,并没有担当其它的职位。这时我们就可以使用组合模式来进行组合。
按照管理层来看,学生职位中最大的是学生会主席,学生会主席下有学生会委员,然后学生会委员又管理着普通的学生,他们之间相互独立,可以成为一个部分,也可以最终成为一个整体。可以说非常符合组合模式中的树形结构以表示‘部分-整体’的层次结构
。
废话不在多说了,下面进行代码的开发。
首先定义一个学生类,有学生姓名和职位属性。
然后在学生类中在添加 add()、remove()、get()方法,最后进行层级调用。
代码示例:
class student{ private string name; private string position; private list<student> students; public student(string name, string position) { this.name = name; this.position = position; students=new arraylist<student>(); } public void add(student student){ students.add(student); } public void remove(student student){ students.remove(student); } public list<student> get(){ return students; } @override public string tostring() { return "student [name=" + name + ", position=" + position + "]"; } } public class compositetest { public static void main(string[] args) { student studentleader=new student("小明","学生会主席"); student committeemember=new student("小刚","学生会委员"); student student=new student("小红","学生"); committeemember.add(student); studentleader.add(committeemember); system.out.println("-"+studentleader); studentleader.get().foreach(sl->{ system.out.println("--"+sl); sl.get().foreach(cm->{ system.out.println("---"+cm); }); }); } }
输出结果:
-student [name=小明, position=学生会主席] --student [name=小刚, position=学生会委员] ---student [name=小红, position=学生]
在上述示例中,我们添加了三个学生(更多也一样,主要是思路),在学校中分别扮演 学生会主席、学生会委员以及学生。其中学生会主席管理着学生会委员,学生会委员管理着学生,他们之间属于层级关系,一层层的包含。在这之中,我们也发现一点,其实组合模式就是把某个对象去包含另一个对象,然后通过组合的方式来进行一些布局。
组合模式的优点:
高层模块调用较为简单,增加某个节点方便。
组合模式的缺点:
因为其子节点的声明都是实现类,而不是接口,违反了依赖倒置原则。
使用场景:
可以表示为 ‘部分-整体’的层级结构。
过滤器模式
简介
过滤器模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。
简单的来说该模式的功能就是如其名,做一个过滤的作用。我们在一般在进行后台接口开发的时候,也会根据过滤掉一些请求。其实过滤器模式主要实现也是这种功能,废话不多说,开始用代码进行相应的说明。
这里依旧用学生来进行讲解,学校的学生中有男生和女生,学校又有不同的年级,这时我们想统计下学生的相关信息,就可以使用过滤器模式来进行分组了。比如,统计该学校有多少男生,一年级的女生有多少,三年级的学生或者女生有多少之类等等。
代码示例:
由于代码有点多,这里就分开进行讲解。
首先定义一个实体类,有姓名、性别、年级这三个属性。
class student{ private string name; private string gender; private integer grade; public student(string name, string gender, integer grade) { super(); this.name = name; this.gender = gender; this.grade = grade; } public string getname() { return name; } public void setname(string name) { this.name = name; } public string getgender() { return gender; } public void setgender(string gender) { this.gender = gender; } public integer getgrade() { return grade; } public void setgrade(integer grade) { this.grade = grade; } @override public string tostring() { return "student [name=" + name + ", gender=" + gender + ", grade=" + grade + "]"; } }
然后再定义一个公用的接口,指定实现的方法。
interface filteringrule { list<student> filter(list<student> students); }
然后再实现该接口,制定不同的过滤规则。这里主要是三种规则,普通的过滤,且过滤,或过滤。
具体实现的方法如下:
class malestudents implements filteringrule{ @override public list<student> filter(list<student> students) { list<student> malestudents = new arraylist<student>(); students.foreach(student->{ if(student.getgender().equalsignorecase("male")){ malestudents.add(student); } }); return malestudents; } } class femalestudents implements filteringrule{ @override public list<student> filter(list<student> students) { list<student> femalestudents = new arraylist<student>(); students.foreach(student->{ if(student.getgender().equalsignorecase("female")){ femalestudents.add(student); } }); return femalestudents; } } class secondgrade implements filteringrule{ @override public list<student> filter(list<student> students) { list<student> secondgradestudents = new arraylist<student>(); students.foreach(student->{ if(student.getgrade() == 2){ secondgradestudents.add(student); } }); return secondgradestudents; } } class and implements filteringrule{ private filteringrule filter; private filteringrule filter2; public and(filteringrule filter,filteringrule filter2) { this.filter=filter; this.filter2=filter2; } @override public list<student> filter(list<student> students) { list<student> students2=filter.filter(students); return filter2.filter(students2); } } class or implements filteringrule{ private filteringrule filter; private filteringrule filter2; public or(filteringrule filter,filteringrule filter2) { this.filter=filter; this.filter2=filter2; } @override public list<student> filter(list<student> students) { list<student> students1=filter.filter(students); list<student> students2=filter2.filter(students); students2.foreach(student->{ if(!students1.contains(student)){ students1.add(student); } }); return students1; } }
最后再来进行调用测试,添加一些学生,并且指定性别以及班级。然后根据不同的条件来进行过滤。
public class filtertest { public static void main(string[] args) { list<student> list=new arraylist<student>(); list.add(new student("小明", "male", 1));//男 list.add(new student("小红", "female", 2));//女 list.add(new student("小刚", "male", 2)); list.add(new student("小霞", "female", 3)); list.add(new student("小智", "male", 3)); list.add(new student("虚无境", "male", 1)); filteringrule male = new malestudents(); filteringrule female = new femalestudents(); filteringrule secondgrade = new secondgrade(); filteringrule secondgrademale = new and(secondgrade, male); filteringrule secondgradeorfemale = new or(secondgrade, female); system.out.println("男生:"+male.filter(list)); system.out.println("女生:"+female.filter(list)); system.out.println("二年级学生:"+secondgrade.filter(list)); system.out.println("二年级男生:"+secondgrademale.filter(list)); system.out.println("二年级的学生或女生:"+secondgradeorfemale.filter(list)); } }
输出结果:
男生:[student [name=小明, gender=male, grade=1], student [name=小刚, gender=male, grade=2], student [name=小智, gender=male, grade=3], student [name=虚无境, gender=male, grade=1]] 女生:[student [name=小红, gender=female, grade=2], student [name=小霞, gender=female, grade=3]] 二年级学生:[student [name=小红, gender=female, grade=2], student [name=小刚, gender=male, grade=2]] 二年级男生:[student [name=小刚, gender=male, grade=2]] 二年级的学生或女生:[student [name=小红, gender=female, grade=2], student [name=小刚, gender=male, grade=2], student [name=小霞, gender=female, grade=3]]
通过上述示例,我们发现过滤器模式其实很简单,制定过滤规则,然后再根据制定的标准来进行过滤,得到符合条件的数据。过滤器模式虽然简单,但是在构建过滤规则的时候,有点繁琐,不过在jdk1.8之后,我们可以使用stream流更方便的进行规则的制定(这一点留在以后再讲)。
过滤器模式的优点:
简单,解耦,使用方便。
过滤器模式的缺点:
好像没有。。。
使用场景:
需要进行筛选的时候。