真实的生活是,认真做好每一天你分内的事情。不索取目前与你无关的爱与远景。不纠缠于多余情绪和评断。不妄想,不在其中自我沉醉。不伤害,不与自己和他人为敌。不表演,也不相信他人的表演。
设计模式学习,近期我会把23中设计模式都写成博客,敬请期待~
—2021/1/17
定义
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
应用场景
假设期末考试要公布成绩:
成绩分为: 语文 数学
学生分为:小明,小红
如果按照传统方式,加一门学科,或者加一个学生,就要改变原有的代码,违背了开闭原则(对扩展开放.对修改关闭),这里就用到了访问者模式
UML类图(1.1)
:
-
红框:被访问者(成绩)
-
黄框:访问者(学生)
-
ObjectStructure聚合了成绩和学生,在调用的时候,和ObjectStructure交互即可.
角色分析
-
Achievement():被访问者接口
-
Chinese() / Mathematics() :被访问者接口实现
-
Student() : 访问者接口
-
XiaoMing() / XiaoHong() : 访问者接口实现
-
ObjectStructure() : 结构对象角色,这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
我理解的ObjectStructure():避免访问者与被访问者直接交互,遵守迪米特原则 (最少知道原则) 迪米特原则定义之一: 一个类对自己依赖的类知道的越少越好,你的东西也别让我知道(不对外泄露信息)
代码实现
Achievement成绩接口:
public interface Achievement {
//分数
void fraction();
}
Chinese语文成绩,实现成绩接口:
public class Chinese implements Achievement {
//姓名
private final String name;
//分数
private final double fraction;
//传递姓名和分数
public Chinese(String name ,double fraction) {
this.fraction = fraction;
this.name = name;
}
@Override
public void fraction() {
Log.i("访问者模式",name+" 的语文成绩为 "+fraction+" 分");
}
}
Mathematics数学成绩,实现成绩接口:
public class Mathematics implements Achievement {
//姓名
private final String name;
//分数
private final double fraction;
public Mathematics(String name ,double fraction) {
this.fraction = fraction;
this.name = name;
}
@Override
public void fraction() {
Log.i("访问者模式",name+" 的数学成绩为 "+fraction+" 分");
}
}
Student学生接口,将成绩接口聚合进来:
public interface Student {
//具体学生
void student(Achievement achievement);
}
XiaoMing小明,实现学生接口:
public class XiaoMing implements Student {
@Override
public void student(Achievement achievement) {
//小明成绩
achievement.fraction();
}
}
XiaoHong小红,实现学生接口:
public class XiaoHong implements Student {
@Override
public void student(Achievement achievement) {
achievement.fraction();
}
}
ObjectStructure,结构对象角色,(遵守迪米特原则):
public class ObjectStructure {
/**
* //输出成绩
* @param student 具体学生
* @param achievement 具体要除数的分数
*/
public void outputAchievement(Student student,Achievement achievement){
student.student(achievement);
}
}
测试代码(客户端):
//小明
XiaoMing xiaoMing = new XiaoMing();
//小红
XiaoHong xiaoHong = new XiaoHong();
//小明语文成绩
Chinese chinese1 = new Chinese("小明",67);
//小红语文成绩
Chinese chinese2 = new Chinese("小红",100);
//小明数学成绩
Mathematics mathematics = new Mathematics("小明",43);
//结构对象角色
ObjectStructure objectStructure = new ObjectStructure();
xiaoMing.student(chinese1);
objectStructure.outputAchievement(xiaoMing,chinese1);
objectStructure.outputAchievement(xiaoHong,chinese2);
objectStructure.outputAchievement(xiaoMing,mathematics);
Log图(2.1)
:
如何进行扩展
比如现在需要添加一门英语,一位同学叫小张:
English英语成绩,实现成绩接口:
public class English implements Achievement{
//姓名
private final String name;
//分数
private final double fraction;
public English(String name ,double fraction) {
this.fraction = fraction;
this.name = name;
}
@Override
public void fraction() {
Log.i("访问者模式",name+" 的英语成绩为 "+fraction+" 分");
}
}
XiaoZhang学生,实现学生接口:
public class XiaoZhang implements Student {
@Override
public void student(Achievement achievement) {
achievement.fraction();
}
}
测试代码(客户端):
//小张
XiaoZhang xiaoZhang = new XiaoZhang();
//英语成绩
English english = new English("小张", 55);
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.outputAchievement(xiaoZhang,english);
Log图(2.2)
:
总结:
- 遵守了迪米特原则(只与直接朋友通信,一个类对自己依赖的类知道的越少越好,不对外泄露信息)这里指ObjectStructure
- 遵守了开闭原则(对扩展开放,对修改关闭):这里指添加英语和小张同学扩展,扩展性良好
- 遵守了单一职责原则:(一个类负责一项职责,而非一个类负责一个职责),这里指 成绩 / 学生 对应的实现类
原创不易,您的点赞就是对我最大的支持哦~