设计模式系列篇

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

2020-09-06  本文已影响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

写在最后

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

上一篇下一篇

猜你喜欢

热点阅读