学生
和 老师
就是一个固定信息的内容,而想让不同视角的用户获取关心的信息,就比较适合使用访问者模式来实现,从而让实体与业务解耦,增强扩展性。
访问者模式的类结构相对其他设计模式来说比较复杂,但这样的设计模式能阔开你对代码结构的新认知,用这样的思维不断的建设处更好的代码架构。
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.62version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.5version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<version>1.7.5version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.0.9version>
<exclusions>
<exclusion>
<artifactId>slf4j-apiartifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
dependencies>
design-step-22
|——src
|——main
|--java
|--com.lino.design
|--user
| |--impl
| | |--Student.java
| | |--Teacher.java
| |--User.java
|--visitor
| |--impl
| | |--Parent.java
| | |--Principal.java
| |--Visitor.java
|-DataView.java
|--test
|--com.lino.design.test
|-ApiTest.java
visitor.visit(this)
,这个方法在每一个用户实现类里,包括:Student
、Teacher
。User.java
package com.lino.design.user;
import com.lino.design.visitor.Visitor;
/**
* @description: 用户类
*/
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;
}
/**
* 核心访问方法
*
* @param visitor 访问者
*/
public abstract void accept(Visitor visitor);
}
abstract void accept(Visitor visitor)
,这个方法是为了让后续的用户具体实现者都能提供出一个访问方法,供外部使用。Student.java
package com.lino.design.user.impl;
import com.lino.design.user.User;
import com.lino.design.visitor.Visitor;
import java.util.Random;
/**
* @description: 学生类
*/
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);
}
/**
* 数量
*/
public int count() {
return 105 - new Random().nextInt(10);
}
}
Teacher.java
package com.lino.design.user.impl;
import com.lino.design.user.User;
import com.lino.design.visitor.Visitor;
import java.math.BigDecimal;
import java.util.Random;
/**
* @description: 老师类
*/
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();
}
}
accept
方法中,提供了本地对象的访问。visitor.visit(this);
entranceRatio
)、排名(ranking
),类似这样的方法可以按照业务需求进行扩展。Visitor.java
package com.lino.design.visitor;
import com.lino.design.user.impl.Student;
import com.lino.design.user.impl.Teacher;
/**
* @description: 访问者接口
*/
public interface Visitor {
/**
* 访问学生信息
*
* @param student 学生类
*/
void visit(Student student);
/**
* 访问老师信息
*
* @param teacher 老师类
*/
void visit(Teacher teacher);
}
升学率和排名
。Parent.java
package com.lino.design.visitor.impl;
import com.lino.design.user.impl.Student;
import com.lino.design.user.impl.Teacher;
import com.lino.design.visitor.Visitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @description: 家长类
*/
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);
}
}
Principal.java
package com.lino.design.visitor.impl;
import com.lino.design.user.impl.Student;
import com.lino.design.user.impl.Teacher;
import com.lino.design.visitor.Visitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @description: 校长类
*/
public class Principal implements Visitor {
private Logger logger = LoggerFactory.getLogger(Principal.class);
@Override
public void visit(Student student) {
logger.info("学生信息 班级:{} 人数:{}", student.clazz, student.count());
}
@Override
public void visit(Teacher teacher) {
logger.info("老师信息 姓名:{} 班级:{} 升学率:{}", teacher.name, teacher.clazz, teacher.entranceRatio());
}
}
DataView.java
package com.lino.design;
import com.lino.design.user.User;
import com.lino.design.user.impl.Student;
import com.lino.design.user.impl.Teacher;
import com.lino.design.visitor.Visitor;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 数据看板
*/
public class DataView {
List<User> userList = new ArrayList<>();
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.java
package com.lino.design.test;
import com.lino.design.DataView;
import com.lino.design.visitor.impl.Parent;
import com.lino.design.visitor.impl.Principal;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @description: 单元测试
*/
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test_show() {
DataView dataView = new DataView();
logger.info("\r\n家长视角访问:");
dataView.show(new Parent());
logger.info("\r\n校长视角访问:");
dataView.show(new Principal());
}
}
new JDNetMall
、 new DangDangNetMall
、 new TaoBaoNetMall
测试结果
14:14:27.268 [main] INFO com.lino.design.test.ApiTest -
家长视角访问:
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 学生信息 姓名:谢飞机 班级:一年一班 排名:47
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 学生信息 姓名:windy 班级:一年一班 排名:26
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 学生信息 姓名:大毛 班级:二年三班 排名:46
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 学生信息 姓名:Shing 班级:三年四班 排名:2
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 老师信息 姓名:BK 班级:一年一班 级别:特级教师
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 老师信息 姓名:娜娜Goddess 班级:一年一班 级别:特级教师
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 老师信息 姓名:dangdang 班级:二年三班 级别:普通教师
14:14:27.273 [main] INFO com.lino.design.visitor.impl.Parent - 老师信息 姓名:泽东 班级:三年四班 级别:实习教师
14:14:27.273 [main] INFO com.lino.design.test.ApiTest -
校长视角访问:
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 学生信息 班级:一年一班 人数:102
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 学生信息 班级:一年一班 人数:103
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 学生信息 班级:二年三班 人数:98
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 学生信息 班级:三年四班 人数:99
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 老师信息 姓名:BK 班级:一年一班 升学率:45.81
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 老师信息 姓名:娜娜Goddess 班级:一年一班 升学率:27.52
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 老师信息 姓名:dangdang 班级:二年三班 升学率:51.94
14:14:27.273 [main] INFO c.lino.design.visitor.impl.Principal - 老师信息 姓名:泽东 班级:三年四班 升学率:37.5
排名:47
、排名:26
、排名:46
、排名:2
。升学率:45.81
、升学率:27.52
、升学率:51.94
、升学率:37.5
。if
判断或者类的强制转换。