• 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流更方便的进行规则的制定(这一点留在以后再讲)。

    过滤器模式的优点:

    简单,解耦,使用方便。

    过滤器模式的缺点:

    好像没有。。。

    使用场景:

    需要进行筛选的时候。

  • 相关阅读:
    Intent
    What should we do next in general after collecting relevant data
    NOTE FOR Secure Friend Discovery in Mobile Social Networks
    missing pcap.h
    after building Android Source code
    plot point(one column)
    When talking to someone else, don't infer that is has been talked with others at first. It may bring repulsion to the person who is talking with you.
    进程基本知识
    Python input和raw_input的区别
    强制 code review:reviewboard+svn 的方案
  • 原文地址:https://www.cnblogs.com/xiaoshen666/p/12519257.html
Copyright © 2020-2023  润新知