美文网首页设计模式系列篇
设计模式系列篇(十八)——访问者模式

设计模式系列篇(十八)——访问者模式

作者: 复旦猿 | 来源:发表于2020-09-06 00:19 被阅读0次

    What

    访问者模式(Visitor Pattern),允许一个或者多个操作应用到一组对象上,解耦操作和对象本身。我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

    Why

    1. 符合单一职责原则。 访问者模式将操作和对象解耦,每个类的职责非常单一。
    2. 优秀的扩展性。 如果想增加操作类型,无须对已有的稳定的对象类进行更改,具有很好的扩展性。
    3. 灵活性。优秀扩展性的必然结果,使得增加或删除操作类型都很方便。

    When

    1. 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
    2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

    How

    访问者模式的实现是比较难理解的,但访问者的实现大家不必掌握,只需要见到能认出是访问者模式就好了。
    下面,我们以实验室年底考核产生报表为例介绍访问者模式的实现。年底了,你的实验室迎来了一年一度的考核,实验室参与年终考核的有学硕和专硕,考核官包括导师和辅导员。对于导师来说,他关注的是学生的科研或者项目情况,而辅导员则更关注学生的课程成绩和社会实践。在这个例子中,学硕和专硕就是对象;而学生的科研、项目情况就是操作,而访问者的类型包括导师和辅导员。
    UML图如下所示:


    访问者模式

    包含以下几部分:

    1. Visitor:接口或者抽象类,定义了对每个 Master子类 访问的行为,它的参数就是被访问的元素,它的方法个数理论上与元素的个数是一样的,因此,访问者模式要求元素的类型要稳定,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式。
    2. ConcreteVisitor:具体的访问者,如本例中的MentorVisitor,它需要给出对每一个元素类访问时所产生的具体行为。
    3. Master:元素接口或者抽象类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。
    4. AcademicMaster、EngineerMaster:具体的元素类,它提供接受访问的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
      具体代码如下:
      首先是Master及其子类。
    // 硕士抽象类,定义基本属性,并定义accept方法,参数为 Vistor 对象。
    public abstract class Master {
        private String name;
        private Double gpa;
        private Double socialPractice;
        private Integer paperCount;
        private Integer projectCount;
    
        public Master(String name, Double gpa, Double socialPractice, Integer paperCount, Integer projectCount) {
            this.name = name;
            this.gpa = gpa;
            this.socialPractice = socialPractice;
            this.paperCount = paperCount;
            this.projectCount = projectCount;
        }
    
        // 省略getter方法
        public abstract void accept(Visitor visitor);
    }
    
    // 学硕类
    public class AcademicMaster extends Master {
        public AcademicMaster(String name, Double gpa, Double socialPractice, Integer paperCount, Integer projectCount) {
            super(name, gpa, socialPractice, paperCount, projectCount);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }
    
    // 专硕类
    public class EngineerMaster extends Master {
        public EngineerMaster(String name, Double gpa, Double socialPractice, Integer paperCount, Integer projectCount) {
            super(name, gpa, socialPractice, paperCount, projectCount);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }
    

    接下来是Visitor接口及其实现类。

    public interface Visitor {
        void visit(AcademicMaster academicMaster);
    
        void visit(EngineerMaster engineerMaster);
    }
    
    // 导师报表
    public class MentorVisitor implements Visitor {
        @Override
        public void visit(AcademicMaster academicMaster) {
            System.out.println(String.format("name: %s, paper count: %d",
                    academicMaster.getName(), academicMaster.getPaperCount()));
        }
    
        @Override
        public void visit(EngineerMaster engineerMaster) {
            System.out.println(String.format("name: %s, project count: %d",
                    engineerMaster.getName(), engineerMaster.getProjectCount()));
        }
    }
    
    // 辅导员报表
    public class CounselorVisitor implements Visitor {
        @Override
        public void visit(AcademicMaster academicMaster) {
            System.out.println(String.format("name: %s, gpa: %f",
                    academicMaster.getName(), academicMaster.getGpa()));
        }
    
        @Override
        public void visit(EngineerMaster engineerMaster) {
            System.out.println(String.format("name: %s, social practice: %f",
                    engineerMaster.getName(), engineerMaster.getSocialPractice()));
        }
    }
    

    通过上面两部分代码,大家可以看出,对Master类对象的操作都集中在Visitor实现中,这就实现了对象元素和操作解耦。如果增加访问者,如家长或者院领导都无须修改Master类,只需要增加相应的访问者实现就可以了。

    最后,给个测试类。

    public class TestMain {
        public static void main(String[] args) {
            Master academicMaster1 = new AcademicMaster("Jeremy", 3.7, 3.0, 1, 3);
            Master academicMaster2 = new AcademicMaster("Bob", 3.2, 2.0, 2, 1);
            Master engineerMaster1 = new EngineerMaster("Tom", 3.3, 4.0, 0, 1);
            Master engineerMaster2 = new EngineerMaster("Amy", 3.0, 3.0, 1, 2);
            List<Master> masters = new ArrayList<>();
            masters.add(academicMaster1);
            masters.add(academicMaster2);
            masters.add(engineerMaster1);
            masters.add(engineerMaster2);
    
            System.out.println("-----mentor's report-----");
            Visitor mentorVisitor = new MentorVisitor();
            for (Master master : masters) {
                master.accept(mentorVisitor);
            }
    
            System.out.println("-----counselor's report-----");
            Visitor counselorVisitor = new CounselorVisitor();
            for (Master master : masters) {
                master.accept(counselorVisitor);
            }
        }
    }
    

    输出如下:

    -----mentor's report-----
    name: Jeremy, paper count: 1
    name: Bob, paper count: 2
    name: Tom, project count: 1
    name: Amy, project count: 2
    -----counselor's report-----
    name: Jeremy, gpa: 3.700000
    name: Bob, gpa: 3.200000
    name: Tom, social practice: 4.000000
    name: Amy, social practice: 3.000000
    

    搞定。

    代码地址

    i-learning

    写在最后

    如果你觉得我写的文章帮到了你,欢迎点赞、评论、分享、赞赏哦,你们的鼓励是我不断创作的动力~

    相关文章

      网友评论

        本文标题:设计模式系列篇(十八)——访问者模式

        本文链接:https://www.haomeiwen.com/subject/uqqqektx.html