2021年7月28日星期三

访问者模式(学习笔记)

  1. 意图

  表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

  2. 动机   

  假如你的团队开发了一款能够使用巨型图像中地理信息的应用程序。图像中的每个节点既能代表复杂实体(例如一座城市),也能代表更精细的对象(例如工业区和旅游景点等)。如果节点代表的真实对象之间存在公路,那么这些节点就会相互连接。在程序内部,每个节点的类型都由其所属的类来表示,每个特定的节点则是一个对象。

         

  一段时间后,接到了实现将图像导出到

 

  此外,他还质疑在节点类中包含导出

  访问者模式建议将新行为放入一个名为访问者的独立类中,而不是试图将其整合到已有类中。现在,需要执行操作的原始对象将作为参数被传递给访问者中的方法,让方法能访问对象所包含的一切必要数据。  

  如果现在该操作能在不同类的对象上执行会怎么样呢?比如在我们的示例中,各节点类导出

class ExportVisitor implements Visitor is method doForCity(City c) { ... } method doForIndustry(Industry f) { ... } method doForSightSeeing(SightSeeing ss) { ... } // ...

  问题是,我们该如何调用这些方法呢?可以发现,这些方法的签名各不相同,因此不能使用多态机制。为了可以挑选出能够处理特定对象的访问者方法,我们需要对它的类进行检查,如下面代码所示:

foreach (Node node in graph) if (node instanceof City)  exportVisitor.doForCity((City) node) if (node instanceof Industry)  exportVisitor.doForIndustry((Industry) node) // ...}

  可否使用方法地重载呢?依然不行,因为我们无法提前知晓节点对象所属的类,所以重载机制无法执行正确的方法

  访问者模式可以解决这个问题。它使用了一种名为双分派(在选择一个方法的时候,不仅仅要根据消息接收者(receiver)的运行时型别(Run time type),还要根据参数的运行时型别(Run time type)。这里的消息接收者其实就是方法的调用者。具体来讲就是,对于消息表达式a.m(b),双分派能够按照a和b的实际类型为其绑定对应方法体)的技巧,在不使用累赘的条件语句地情况下,也可以执行正确的方法。与其让客户端来选择调用正确版本的方法,不如将对象放在各个节点中,并将访问者对象作为参数传给该对象。由于该对象知晓其自身的类,因此能更自然地在访问者中选出正确的方法。它们会 "接收" 一个访问者并告诉其应执行的访问者方法

// 客户端代码foreach (Node node in graph) node.accept(exportVisitor)// 城市class City is method accept(Visitor v) is  v.doForCity(this) // ...// 工业区class Industry is method accept(Visitor v) is  v.doForIndustry(this) // ...

  我们最终还是修改了节点类,但毕竟改动很小,而且在后续进一步添加行为时无需再次修改代码。现在,如果我们抽取出所有访问者的通用接口,所有已有的节点都能与我们在程序中引入的任何访问者交互。如果需要引入与节点相关的某个行为,你只需要实现一个新的访问者类即可  

  3. 适用性

  • 一个对象结构(如对象树)包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作
  • 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作污染这些类对象。Visitor使得你可以将相关操作集中起来定义在一个类中。当对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作
  • 当某个行为仅在类层次结构中的一些类中有意义,而在其他类中没有意义时,可使用该模式

  4. 结构

                                       

  5. 效果

  1. 访问者模式使得易于增加新的操作(开闭原则)

  2. 访问者集中相关的操作而分离无关的操作(单一职责原则)

  3. 增加新的ConcreteElement类很困难    Visitor模式使得难以增加新的Element的子类。每添加一个新的ConcreteElement都要在Visitor中添加一个新的抽象操作,并在每一个ConcreteVisitor类中实现相应的操作。所以在使用访问者模式时考虑的关键问题是系统的哪个部分会经常变化,是作用于对象结构上的算法还是构成该结构的给个对象的类。如果总是有新的ConcreteElement类加进来,Visitor类层次将变得难以维护

  4. 在访问者同某个元素进行交互时,它们可能没有访问元素私有成员变量和方法的必要权限

  6. 代码实现    

  在本例中, 我们希望将一系列几何形状导出为 。 重点在于我们不希望直接修改形状代码, 或者至少能确保最小程度的修改。

  shapes/Shape.java: 通用形状接口

package visitor.shapes;import visitor.visitor.Visitor;/** * @author GaoMing * @date 2021/7/26 - 17:23 */public interface Shape { void move(int x, int y); void draw(); String accept(Visitor visitor);}

  shapes/Dot.java: 点

package visitor.shapes;import visitor.visitor.Visitor;/** * @author GaoMing * @date 2021/7/26 - 17:24 */public class Dot implements Shape{ private int id; private int x; private int y; public Dot() { } public Dot(int id, int x, int y) {  this.id = id;  this.x = x;  this.y = y; } @Override public void move(int x, int y) {  // move shape } @Override public void draw() {  // draw shape } @Override public String accept(Visitor visitor) {  return visitor.visitDot(this); } public int getX() {  return x; } public int getY() {  return y; } public int getId() {  return id; }}

  shapes/Circle.java: 圆形

package visitor.shapes;import visitor.visitor.Visitor;/** * @author GaoMing * @date 2021/7/26 - 17:25 */public class Circle extends Dot{ private int radius; public Circle(int id, int x, int y, int radius) {  super(id, x, y);  this.radius = radius; } @Override public String accept(Visitor visitor) {  return visitor.visitCircle(this); } public int getRadius() {  return radius; }}

  shapes/Rectangle.java: 矩形

package visitor.shapes;import visitor.visitor.Visitor;/** * @author GaoMing * @date 2021/7/26 - 17:26 */public class Rectangle implements Shape{ private int id; private int x; private int y; private int width; private int height; public Rectangle(int id, int x, int y, int width, int height) {  this.id = id;  this.x = x;  this.y = y;  this.width = width;  this.height = height; } @Override public String accept(Visitor visitor) {  return visitor.visitRectangle(this); } @Override public void move(int x, int y) {  // move shape } @Override public void draw() {  // draw shape } public int getId() {  return id; } public int getX() {  return x; } public int getY() {  return y; } public int getWidth() {  return width; } public int getHeight() {  return height; }}

  shapes/CompoundShape.java: 组合形状

package visitor.shapes;import visitor.visitor.Visitor;import java.util.ArrayList;import java.util.List;/** * @author GaoMing * @date 2021/7/26 - 17:27 */public class CompoundShape implements Shape{ public int id; public List<Shape> children = new ArrayList<>(); public CompoundShape(int id) {  this.id = id; } @Override public void move(int x, int y) {  // move shape } @Override public void draw() {  // draw shape } public int getId() {  return id; } @Override public String accept(Visitor visitor) {  return visitor.visitCompoundGraphic(this); } public void add(Shape shape) {  children.add(shape); }}

  visitor/Visitor.java: 通用访问者接口

package visitor.visitor;import visitor.shapes.Circle;import visitor.shapes.CompoundShape;import visitor.shapes.Dot;import visitor.shapes.Rectangle;/** * @author GaoMing * @date 2021/7/26 - 17:24 */public interface Visitor { String visitDot(Dot dot); String visitCircle(Circle circle); String visitRectangle(Rectangle rectangle); String visitCompoundGraphic(CompoundShape cg);}

  visitor/

package visitor.visitor;import visitor.shapes.*;/** * @author GaoMing * @date 2021/7/26 - 17:28 */public class implements Visitor{ public String export(Shape... args) {  StringBuilder sb = new StringBuilder();  sb.append("<?);  for (Shape shape : args) {   sb.append(shape.accept(this)).append("\n");  }  return sb.toString(); } public String visitDot(Dot d) {  return "<dot>" + "\n" +    " <id>" + d.getId() + "</id>" + "\n" +    " <x>" + d.getX() + "</x>" + "\n" +    " <y>" + d.getY() + "</y>" + "\n" +    "</dot>"; } public String visitCircle(Circle c) {  return "<circle>" + "\n" +    " <id>" + c.getId() + "</id>" + "\n" +    " <x>" + c.getX() + "</x>" + "\n" +    " <y>" + c.getY() + "<......

原文转载:http://www.shaoqun.com/a/902601.html

跨境电商:https://www.ikjzd.com/

墩煌网:https://www.ikjzd.com/w/189

wangwei:https://www.ikjzd.com/w/1744

mav:https://www.ikjzd.com/w/2414


1.意图  表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作  2.动机    假如你的团队开发了一款能够使用巨型图像中地理信息的应用程序。图像中的每个节点既能代表复杂实体(例如一座城市),也能代表更精细的对象(例如工业区和旅游景点等)。如果节点代表的真实对象之间存在公路,那么这些节点就会相互连接。在程序内部,每个节点的类型都由其所属的类来表
急速:https://www.ikjzd.com/w/1861
这就是昆明 | 花枝不断四时春,五彩之南温柔乡:http://www.30bags.com/a/226136.html
这就是日本的农村了,干净,萧条,一息尚存。——斜阳馆:http://www.30bags.com/a/245016.html
这就是中国和俄罗斯的边境,眼前这一幕,让男游客看得挪不开眼:http://www.30bags.com/a/248627.html
这就是中华第一高瀑,网红都来打卡,震撼二个字写在镜头里_文成:http://www.30bags.com/a/221142.html
"艳照门"背后的大手:http://lady.shaoqun.com/a/49534.html
同时和两个黑人老外做 一个添上面二个㖭下面:http://lady.shaoqun.com/m/a/247912.html
你太大了岳你太紧疼了 岳两腿中间流水了:http://www.30bags.com/m/a/249859.html
Tik Tok代运营丨Tik Tok达人计划又是什么?:https://www.ikjzd.com/articles/146994
"我和400多个女孩上过床,但我知道我是一名优秀的归国PUA家庭教师。":http://lady.shaoqun.com/a/439510.html
哦,我的上帝!36岁的马谡实际上穿着迷你裙坐在沙溢上。网友:有亮点:http://lady.shaoqun.com/a/439511.html
多好的动物啊!男人在朋友女儿面前强奸朋友妻子:http://lady.shaoqun.com/a/439512.html

没有评论:

发表评论