访问者模式:指将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作。为数据结构中的每个元素提供多种访问方式。
模拟场景:
1、在本案例中我们模拟校园中的学⽣和⽼师对于不同⽤户的访问视⻆这个案例场景我们模拟校园中有学⽣和⽼师两种身份的⽤户,那么对于家⻓和校⻓关⼼的⻆度来看,他们的视⻆是不同的。
家⻓更关⼼孩⼦的成绩和⽼师的能⼒,
校⻓更关⼼⽼师所在班级学⽣的⼈数和升学率{ 此处模拟的 }。
教师和学生都继承此类,姓名,身份,班级等基础属性
package com.qf.design.behavior.visitor.design.user;
import com.qf.design.behavior.visitor.design.visitor.Visitor;
public abstract class User {
//姓名
public String name;
// 身份;重点班、普通班 | 特级教师、普通教师、实习教师
public String identity;
//班级
public String clazz;
public User(String name, String identity, String clazz){
this.name=name;
this.identity=identity;
this.clazz=clazz;
}
// 核⼼访问⽅法
public abstract void accept(Visitor visitor);
}
学生:扩展ranking排名
package com.qf.design.behavior.visitor.design.user.impl;
import com.qf.design.behavior.visitor.design.user.User;
import com.qf.design.behavior.visitor.design.visitor.Visitor;
public class Student extends User {
public Student(String name, String identity, String clazz) {
super(name, identity, clazz);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int ranking() {
return (int) (Math.random() * 100);
}
}
老师:entranceRatio升学率
package com.qf.design.behavior.visitor.design.user.impl;
import com.qf.design.behavior.visitor.design.user.User;
import com.qf.design.behavior.visitor.design.visitor.Visitor;
import java.math.BigDecimal;
public class Teacher extends User {
public Teacher(String name, String identity, String clazz) {
super(name, identity, clazz);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 升本率
public double entranceRatio() {
return BigDecimal.valueOf(Math.random() * 100).setScale(2,
BigDecimal.ROUND_HALF_UP).doubleValue();}
}
定义接口,学生和老师,分别对应不同的观察方式
package com.qf.design.behavior.visitor.design.visitor;
import com.qf.design.behavior.visitor.design.user.impl.Student;
import com.qf.design.behavior.visitor.design.user.impl.Teacher;
public interface Visitor {
// 访问学⽣信息
void visit(Student student);
// 访问⽼师信息
void visit(Teacher teacher);
}
家长观察学生和老师
package com.qf.design.behavior.visitor.design.visitor.impl;
import com.qf.design.behavior.visitor.design.user.impl.Student;
import com.qf.design.behavior.visitor.design.user.impl.Teacher;
import com.qf.design.behavior.visitor.design.visitor.Visitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Parent implements Visitor {
private Logger logger = LoggerFactory.getLogger(Parent.class);
@Override
public void visit(Student student) {
logger.info("学⽣信息 姓名:{} 班级:{} 排名:{}", student.name,
student.clazz, student.ranking());
}
@Override
public void visit(Teacher teacher) {
logger.info("⽼师信息 姓名:{} 班级:{} 级别:{}", teacher.name,
teacher.clazz, teacher.identity);
}
}
校长观察学生和老师
package com.qf.design.behavior.visitor.design.visitor.impl;
import com.qf.design.behavior.visitor.design.user.impl.Student;
import com.qf.design.behavior.visitor.design.user.impl.Teacher;
import com.qf.design.behavior.visitor.design.visitor.Visitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Principal implements Visitor {
private Logger logger = LoggerFactory.getLogger(Principal.class);
@Override
public void visit(Student student) {
logger.info("学⽣信息 姓名:{} 班级:{}", student.name,
student.clazz);
}
@Override
public void visit(Teacher teacher) {
logger.info("学⽣信息 姓名:{} 班级:{} 升学率:{}", teacher.name,
teacher.clazz, teacher.entranceRatio());
}
}
数据看板:DataView
package com.qf.design.behavior.visitor.design;
import com.qf.design.behavior.visitor.design.user.User;
import com.qf.design.behavior.visitor.design.user.impl.Student;
import com.qf.design.behavior.visitor.design.user.impl.Teacher;
import com.qf.design.behavior.visitor.design.visitor.Visitor;
import java.util.ArrayList;
import java.util.List;
public class DataView {
List<User> userList = new ArrayList<User>();
public DataView(){
userList.add(new Student("谢⻜机", "᯿点班", "⼀年⼀班"));
userList.add(new Student("windy", "᯿点班", "⼀年⼀班"));
userList.add(new Student("⼤⽑", "普通班", "⼆年三班"));
userList.add(new Student("Shing", "普通班", "三年四班"));
userList.add(new Teacher("BK", "特级教师", "⼀年⼀班"));
userList.add(new Teacher("娜娜Goddess", "特级教师", "⼀年⼀班"));
userList.add(new Teacher("dangdang", "普通教师", "⼆年三班"));
userList.add(new Teacher("泽东", "实习教师", "三年四班"));
}
// 展示
public void show(Visitor visitor) {
for (User user : userList) {
user.accept(visitor);
}
}
}
测试:ApiTest
package com.qf.design.behavior.visitor.design;
import com.qf.design.behavior.visitor.design.visitor.impl.Parent;
import com.qf.design.behavior.visitor.design.visitor.impl.Principal;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(Parent.class);
@Test
public void test(){
DataView dataView = new DataView();
logger.info("\r\n家⻓视⻆访问:");
dataView.show(new Parent()); // 家⻓
logger.info("\r\n校⻓视⻆访问:");
dataView.show(new Principal()); // 校⻓
}
}
总结:
从以上的业务场景中可以看到,在嵌⼊访问者模式后,可以让整个⼯程结构变得容易添加和修改。也就做到了系统服务之间的解耦,不⾄于为了不同类型信息的访问⽽增加很多多余的 if 判断或者类的强制转换。也就是通过这样的设计模式⽽让代码结构更加清晰。
另外在实现的过程可能你可能也发现了,定义抽象类的时候还需要等待访问者接⼝的定义,这样的设计⾸先从实现上会让代码的组织变得有些难度。另外从设计模式原则的⻆度来看,违背了迪⽶特原则,也就是最少知道原则。因此在使⽤上⼀定要符合场景的运⽤,以及提取这部分设计思想的精髓。