行为型模式-访问者模式
- 8.8访问者模式
- 8.8.1概念
- 8.8.2场景
- 8.8.3优势 / 劣势
- 8.8.4访问者模式可分为
- 8.8.5访问者模式
- 8.8.6实战
- 8.8.6.1题目描述
- 8.8.6.2输入描述
- 8.8.6.3输出描述
- 8.8.6.4代码
- 8.8.7总结
8.8访问者模式
8.8.1概念
访问者模式是一种将操作逻辑与对象结构分离的方法,使得操作可以独立变化,操作逻辑被封装在独立的访问者类中,并在被访问的元素类中提供接受访问者的方法,而不是直接嵌入到数据结构中的对象中。
8.8.2场景
我们可以将一个购物商场中的商品类作为元素类,不同的销售人员可以作为访问者类。当销售人员需要对商品进行销售操作时,可以创建一个具体的访问者对象,然后通过商品类的接受访问者的方法将访问者对象传入。然后商品类再根据传入的访问者对象调用相应的访问者方法,从而实现对商品的不同销售策略,如打折、促销等。
8.8.3优势 / 劣势
- 操作逻辑更加独立:将操作逻辑从对象结构中分离出来,使得操作逻辑更加独立和可复用
- 提高代码的可维护性:将操作逻辑封装在独立的访问者类中,使得代码更加清晰易懂
- 不宜测试和维护:访问者模式涉及到多个类的交互,使得测试和维护变得更加困难
- 增加系统复杂性:引入了访问者类和被访问的元素类之间的依赖关系,增加了系统的复杂性
8.8.4访问者模式可分为
- 抽象访问者Visitor:声明了访问者可以访问哪些元素,以及如何访问它们的方法visit
- 具体访问者ConcreteVisitor:实现了抽象访问者定义的方法,不同的元素类型可能有不同的访问行为
- 抽象元素Element:定义了一个accept方法,用于接受访问者的访问
- 具体元素ConcreteElement:实现了accept方法,是访问者访问的目标
- 对象结构Object Structure:包含元素的集合,可以是一个列表、一个集合或其他数据结构,负责遍历元素,并调用元素的接受方法
8.8.5访问者模式
8.8.6实战
8.8.6.1题目描述
小明家有一些圆形和长方形面积的土地,请你帮他实现一个访问者模式,使得可以通过访问者计算每块土地的面积。
图形的面积计算规则如下:
- 圆形的面积计算公式为:3.14 * 半径 * 半径
- 矩形的面积计算公式为:长 * 宽
8.8.6.2输入描述
第一行是一个整数 n(1 <= n <= 1000),表示图形的数量。
接下来的 n 行,每行描述一个图形,格式为 “Circle r” 或 “Rectangle width height”,其中 r、width、height 是正整数。
8.8.6.3输出描述
对于每个图形,输出一行,表示该图形的面积。
8.8.6.4代码
package com.technologystatck.designpattern.mode.visitor;import java.util.Scanner;public class Test {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int nums = scanner.nextInt();scanner.nextLine();//创建数组来存储图形对象Shape[] shapes = new Shape[nums];//根据用户输入来创建不同类型的图形对象for (int i = 0; i < nums; i++) {String[] inputs = scanner.nextLine().split(" ");if (inputs[0].equals("Circle")) {int radius = Integer.parseInt(inputs[1]);shapes[i] = new Circle(radius);} else if (inputs[0].equals("Rectangle")) {int width = Integer.parseInt(inputs[1]);int height = Integer.parseInt(inputs[2]);shapes[i] = new Rectangle(width, height);} else {System.out.println("Invalid input");return;}}//创建图形集合Drawing drawing = new Drawing(shapes);//创建面积计算访问者ConcreteAreaCalc concreteAreaCalc = new ConcreteAreaCalc();drawing.accept(concreteAreaCalc);}
}//访问者接口
interface Visitor {//圆形的访问者方法void visit(Circle circle);//矩形的访问者方法void visit(Rectangle rectangle);
}//实现具体访问者,相当于计算圆形/矩形
class ConcreteAreaCalc implements Visitor {@Overridepublic void visit(Circle circle) {double area = 3.14 * Math.pow(circle.getRadius(), 2);System.out.println(area);}@Overridepublic void visit(Rectangle rectangle) {double area = rectangle.getHeight() * rectangle.getWidth();System.out.println(area);}
}//定义元素接口
interface Shape {void accept(Visitor visitor);
}//实现圆形具体元素
class Circle implements Shape {private int radius;public Circle(int radius) {this.radius = radius;}public int getRadius() {return radius;}@Overridepublic void accept(Visitor visitor) {//调用访问者的方法,访问当前对象,并将当前对象传递给访问者。visitor.visit(this);}
}//实现矩形具体元素
class Rectangle implements Shape {private int width;private int height;public Rectangle(int width, int height) {this.width = width;this.height = height;}public int getWidth() {return width;}public int getHeight() {return height;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}//创造对象结构,用于让访问者访问它的元素
class Drawing {private Shape[] shapes;public Drawing(Shape[] shapes) {this.shapes = shapes;}//循环遍历访问者接口public void accept(Visitor visitor) {for (Shape shape : shapes) {shape.accept(visitor);}}}
8.8.7总结
- 优点:操作逻辑与对象结构分离,以及增加新的操作无需修改原有的代码
- 总结:通过将操作逻辑与对象结构分离,使用抽象访问者用于声明访问者可以访问哪些元素、具体访问者实现了抽象访问者定义的方法,创建具体的访问对象、抽象元素用于接收访问者的访问、具体元素用于被访问者进行访问、对象结构用于存储和遍历元素的集合
- 场景:常用于对象结构比较稳定,但经常需要在此对象结构上定义新的操作