25

重学 Java 设计模式:实战访问者模式「模拟家长与校长,对学生和老师的不同视角信息的...

 3 years ago
source link: http://www.cnblogs.com/xiaofuge/p/13277537.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
JNB73qb.png!web

作者:小傅哥

博客: https://bugstack.cn - 原创系列专题文章

沉淀、分享、成长,让自己和他人都能有所收获!:smile:

一、前言

能力,是你前行的最大保障

年龄会不断的增长,但是什么才能让你不慌张。一定是能力,即使是在一个看似还很安稳的工作中也是一样,只有拥有 能留下的本事跳出去的能力 ,你才会是安稳的。而能力的提升是不断突破自己的未知也就是拓展宽度,以及在专业领域建设个人影响力也就是深度。如果日复日365天,天天搬砖,一切都没有变化的重复只能让手上增长点老茧,岁月又叹人生苦短。

站得高看的远吗?

站得高确实能看得远,也能给自己更多的追求。但,站的高了,原本看的清的东西就变得看不清了。视角和重点的不同,会让我们有很多不同的选择,而脚踏实地是给自己奠定能攀升起来的基石,当真的可以四平八稳的走向山头的时候,才是适合看到更远的时候。

数学好才能学编码吗

往往很多时候学编程的初学者都会问数学不好能学会吗?其实可以想想那为什么数学不好呢?在这条没学好的路上,你为它们付出了多少时间呢?如果一件事情你敢做到和写自己名字一样熟悉,还真的有难的东西吗。从大学到毕业能写出40万行代码的,还能愁找不到工作吗,日积月累,每一天并没有多难。难的你想用最后一个月的时间学完人家四年努力的成绩的。学习,要趁早。

二、开发环境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三个,可以通过关注 公众号 bugstack虫洞栈 ,回复 源码下载 获取(打开获取的链接,找到序号18)
工程 描述 itstack-demo-design-22-00 场景模拟工程;模拟学生和老师信息不同视角访问

三、访问者模式介绍

MjaQJnV.jpg!web

访问者要解决的核心事项是,在一个稳定的数据结构下,例如用户信息、雇员信息等,增加易变的业务访问逻辑。为了增强扩展性,将这两部分的业务解耦的一种设计模式。

v2AZziA.jpg!web

说白了访问者模式的核心在于同一个事物不同视角下的访问信息不同,比如一个 美女 手里拿个 冰激凌 。小朋友会注意冰激凌,大朋友会找自己喜欢的地方观测敌情。

四、案例场景模拟

NjAvm2z.jpg!web

在本案例中我们模拟校园中的学生和老师对于不同用户的访问视角

这个案例场景我们模拟校园中有学生和老师两种身份的用户,那么对于家长和校长关心的角度来看,他们的视角是不同的。家长更关心孩子的成绩和老师的能力,校长更关心老师所在班级学生的人数和升学率{ 此处模拟的 }。

那么这样 学生老师 就是一个固定信息的内容,而想让不同视角的用户获取关心的信息,就比较适合使用观察者模式来实现,从而让实体与业务解耦,增强扩展性。 但观察者模式的整体类结构相对复杂,需要梳理清楚再开发

五、访问者模式搭建工程

访问者模式的类结构相对其他设计模式来说比较复杂,但这样的设计模式在我看来更加 烧气有魅力 ,它能阔开你对代码结构的新认知,用这样思维不断的建设出更好的代码架构。

关于这个案例的核心逻辑实现,有以下几点;

  1. 建立用户抽象类和抽象访问方法,再由不同的用户实现;老师和学生。
  2. 建立访问者接口,用于不同人员的访问操作;校长和家长。
  3. 最终是对数据的看板建设,用于实现不同视角的访问结果输出。

1. 工程结构

itstack-demo-design-22-00
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.design
    │           ├── user
    │           │	  ├── impl
    │           │	  │     ├── Student.java
    │           │	  │     └── Teacher.java
    │           │	  └── User.java   
    │           ├── visitor
    │           │	  ├── impl
    │           │	  │     ├── Parent.java
    │           │	  │     └── Principal.java
    │           │	  └── Visitor.java
    │           └──  DataView.java
    └── test
        └── java
            └── org.itstack.demo.design.test
                └── ApiTest.java

访问者模式模型结构

EZzyEnB.jpg!web

以上是视图展示了代码的核心结构,主要包括不同视角下的不同用户访问模型。

在这里有一个关键的点非常重要,也就是整套设计模式的核心组成部分; visitor.visit(this) ,这个方法在每一个用户实现类里,包括; StudentTeacher 。在以下的实现中可以重点关注。

2. 代码实现

2.1 定义用户抽象类

// 基础用户信息
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);

}
abstract void accept(Visitor visitor)

2.2 实现用户信息(老师和学生)

老师类

public class Teacher extends User {

    public Teacher(String name, String identity, String clazz) {
        super(name, identity, clazz);
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    // 升本率
    public double entranceRatio() {
        return BigDecimal.valueOf(Math.random() * 100).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

}

学生类

public class Student extends User {

    public Student(String name, String identity, String clazz) {
        super(name, identity, clazz);
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public int ranking() {
        return (int) (Math.random() * 100);
    }

}
  • 这里实现了老师和学生类,都提供了父类的构造函数。
  • accept 方法中,提供了本地对象的访问; visitor.visit(this) ,这块需要加深理解。
  • 老师和学生类又都单独提供了各自的特性方法;升本率( entranceRatio )、排名( ranking ),类似这样的方法可以按照业务需求进行扩展。

2.3 定义访问数据接口

public interface Visitor {

    // 访问学生信息
    void visit(Student student);

    // 访问老师信息
    void visit(Teacher teacher);

}
  • 访问的接口比较简单,相同的方法名称,不同的入参用户类型。
  • 让具体的访问者类,在实现时可以关注每一种用户类型的具体访问数据对象,例如;升学率和排名。

2.4 实现访问类型(校长和家长)

访问者;校长

public class Principal implements Visitor {

    private Logger logger = LoggerFactory.getLogger(Principal.class);

    public void visit(Student student) {
        logger.info("学生信息 姓名:{} 班级:{}", student.name, student.clazz);
    }

    public void visit(Teacher teacher) {
        logger.info("学生信息 姓名:{} 班级:{} 升学率:{}", teacher.name, teacher.clazz, teacher.entranceRatio());
    }

}

访问者;家长

public class Parent implements Visitor {

    private Logger logger = LoggerFactory.getLogger(Parent.class);

    public void visit(Student student) {
        logger.info("学生信息 姓名:{} 班级:{} 排名:{}", student.name, student.clazz, student.ranking());
    }

    public void visit(Teacher teacher) {
        logger.info("老师信息 姓名:{} 班级:{} 级别:{}", teacher.name, teacher.clazz, teacher.identity);
    }

}
  • 以上是两个具体的访问者实现类,他们都有自己的视角需求。
  • 校长关注;学生的名称和班级,老师对这个班级的升学率
  • 家长关注;自己家孩子的排名,老师的班级和教学水平

2.5 数据看版

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);
        }
    }

}
观察者(校长、家长)

3. 测试验证

3.1 编写测试类

@Test
public void test(){
    DataView dataView = new DataView();      

    logger.info("\r\n家长视角访问:");
    dataView.show(new Parent());     // 家长

    logger.info("\r\n校长视角访问:");
    dataView.show(new Principal());  // 校长
}
  • 从测试类可以看到,家长和校长分别是不同的访问视角。

3.2 测试结果

23:00:39.726 [main] INFO  org.itstack.demo.design.test.ApiTest - 
家长视角访问:
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 学生信息 姓名:谢飞机 班级:一年一班 排名:62
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 学生信息 姓名:windy 班级:一年一班 排名:51
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 学生信息 姓名:大毛 班级:二年三班 排名:16
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 学生信息 姓名:Shing 班级:三年四班 排名:98
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 老师信息 姓名:BK 班级:一年一班 级别:特级教师
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 老师信息 姓名:娜娜Goddess 班级:一年一班 级别:特级教师
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 老师信息 姓名:dangdang 班级:二年三班 级别:普通教师
23:00:39.730 [main] INFO  o.i.demo.design.visitor.impl.Parent - 老师信息 姓名:泽东 班级:三年四班 级别:实习教师
23:00:39.730 [main] INFO  org.itstack.demo.design.test.ApiTest - 
校长视角访问:
23:00:39.731 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:谢飞机 班级:一年一班
23:00:39.731 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:windy 班级:一年一班
23:00:39.731 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:大毛 班级:二年三班
23:00:39.731 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:Shing 班级:三年四班
23:00:39.733 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:BK 班级:一年一班 升学率:70.62
23:00:39.733 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:娜娜Goddess 班级:一年一班 升学率:23.15
23:00:39.734 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:dangdang 班级:二年三班 升学率:70.98
23:00:39.734 [main] INFO  o.i.d.design.visitor.impl.Principal - 学生信息 姓名:泽东 班级:三年四班 升学率:90.14

Process finished with exit code 0
  • 通过测试结果可以看到,家长和校长的访问视角同步,数据也是差异化的。
  • 家长视角看到学生的排名; 排名:62排名:51排名:16排名:98
  • 校长视角看到班级升学率; 升学率:70.62升学率:23.15升学率:70.98升学率:90.14
  • 通过这样的测试结果,可以看到访问者模式的初心和结果,在适合的场景运用合适的模式,非常有利于程序开发。

六、总结

if

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK