设计模式学习第十五节 访问者模式
概述
基本介绍
1、访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各个元素的操作,它可以在不该拜年数据结构的前提下定义作用于这些元素的新的操作。
2、主要将数据结构于数据操作分离,解决数据结构和操作耦合的问题。
3、访问者模式的基本工作原理是:在被访问类的里面添加一个对外提供接待访问者的接口。
4、访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有什么关联),同时需要避免这些操作污染这些对象的类,可以选用访问者模式。
5、对象结构比较稳定,但经常需要在此对象结构上定义新的操作,使用访问者模式更容易扩展。对象结构不稳定,使用访问者模式会使得程序更加复杂。
6、一句话总结:在结构不变的情况下,动态的改变对于内部元素的访问。
类图
类图说明:
1、Visitor 是抽象访问者,为该对象结构中的ConcreteElement每一个类声明一个Visit操作。
2、ConcreteVisitor:是具体访问者,实现每个Visitor声明的操作,是每个操作具体实现。
3、ObejctStruture:能枚举它的元素,可以提供一个高层的接口,用来允许访问者访问它的元素:
4、Element:定义一个accept()方法,接收一个访问者对象。
5、ConcreteElement:具体元素,实现了accept方法。
代码实现
小需求:组装一台电脑,每个部件针对不同的人群有不同的折扣,比如说,电脑由主机、屏幕、键盘、鼠标构成,结构不再变动。学生人群主机8折、屏幕7折、键盘8折、鼠标8折;公司采购员人群主机6折、屏幕6折、键盘5折、鼠标5折等等。可以使用访问者模式实现,不然就需要在Computer类中添加各种判断,每增加一种人群类型都需要新增一个判断。
根据需求与访问这模式画出类图
代码实现
package com.example.pattern.visitor;
import lombok.Getter;
import lombok.Setter;
/**
* 访问者模式
*/
interface Visitor {
void visitMainframe(Mainframe mainframe);
void visitScreen(Screen screen);
void visitKeyboard(Keyboard keyboard);
void visitMouse(Mouse mouse);
}
@Setter
@Getter
class StudentTypeVisitor implements Visitor {
private Double totalPrice = 0d;
@Override
public void visitMainframe(Mainframe mainframe) {
this.totalPrice += mainframe.getPrice() * 0.8;
}
@Override
public void visitScreen(Screen screen) {
this.totalPrice += screen.getPrice() * 0.9;
}
@Override
public void visitKeyboard(Keyboard keyboard) {
this.totalPrice += keyboard.getPrice() * 0.7;
}
@Override
public void visitMouse(Mouse mouse) {
this.totalPrice += mouse.getPrice() * 0.6;
}
}
@Setter
@Getter
class CorpTypeVisitor implements Visitor {
private Double totalPrice = 0d;
@Override
public void visitMainframe(Mainframe mainframe) {
this.totalPrice += mainframe.getPrice() * 0.7;
}
@Override
public void visitScreen(Screen screen) {
this.totalPrice += screen.getPrice() * 0.6;
}
@Override
public void visitKeyboard(Keyboard keyboard) {
this.totalPrice += keyboard.getPrice() * 0.5;
}
@Override
public void visitMouse(Mouse mouse) {
this.totalPrice += mouse.getPrice() * 0.5;
}
}
@Getter
@Setter
public class Computer { // Computer结构已经被固定 就是这四个模块
private ComputerPart mainframe = new Mainframe(); //主机
private ComputerPart screen = new Screen(); // 屏幕
private ComputerPart keyboard = new Keyboard(); // 键盘
private ComputerPart mouse = new Mouse(); // 鼠标
public void accept(Visitor visitor) {
this.mainframe.accept(visitor);
this.screen.accept(visitor);
this.keyboard.accept(visitor);
this.mouse.accept(visitor);
}
}
abstract class ComputerPart { // 抽象类 电脑的一部分
abstract void accept(Visitor visitor);
abstract Double getPrice();
}
class Mainframe extends ComputerPart { // 主机
@Override
public void accept(Visitor visitor) {
visitor.visitMainframe(this);
}
@Override
public Double getPrice() {
return 5000d;
}
}
class Screen extends ComputerPart { // 屏幕
@Override
public void accept(Visitor visitor) {
visitor.visitScreen(this);
}
@Override
public Double getPrice() {
return 900d;
}
}
class Keyboard extends ComputerPart { // 键盘
@Override
public void accept(Visitor visitor) {
visitor.visitKeyboard(this);
}
@Override
public Double getPrice() {
return 60d;
}
}
class Mouse extends ComputerPart { // 鼠标
@Override
public void accept(Visitor visitor) {
visitor.visitMouse(this);
}
@Override
public Double getPrice() {
return 50d;
}
}
class Client {
public static void main(String[] args) {
Computer computer = new Computer();
StudentTypeVisitor studentTypeVisitor = new StudentTypeVisitor();
computer.accept(studentTypeVisitor);
System.out.println(studentTypeVisitor.getTotalPrice());
CorpTypeVisitor corpTypeVisitor = new CorpTypeVisitor();
computer.accept(corpTypeVisitor);
System.out.println(corpTypeVisitor.getTotalPrice());
// 经过代码实现在添加其它类型的人群是比较简单的,只需要实现 Visitor接口实现方法即可
// 但是如何Computer类结构有变化 比如有耳机模块,整个模式将不再好维护,变得比较复杂。
}
}
使用细节
优点
1、访问这模式符合单一职责原则,让程序具有更好的扩展性。
2、访问者模式可以对功能进行统一,可以做报表等数据结构非常稳定的系统。
缺点
1、具体元素对访问者公布细节,也就是说访问者关注了其它类的内部细节,不符合迪米特法则,这样也就造成了具体元素的变更比较困难,修改起来比较麻烦。
2、违背了依赖倒转原则,访问者依赖的是具体元素,而不是抽象元素。
3、因此访问者模式适合于拥有稳定的数据结构、但是功能经常变化的系统。
本文地址:https://blog.csdn.net/GayFei/article/details/111990722
上一篇: 再见了IF-ELSE,拥抱规则引擎
下一篇: 第10章 化繁为简的翻译机——解释器模式