本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8135083.html,记录一下学习过程以备后续查用。
一、引言
今天我们要讲行为型设计模式的第九个模式--访问者模式。如果按老规矩,先从名称上来看这个模式,我根本不能获得任何对理解该模式有用的信息,而且这个模式在我们的编码生活中使用的并不是很多。该模式的意图定义很抽象,第一次看了这个定义其实和没看没有什么区别,一头雾水。为了让大家更好的理解该模式的初衷,我们举个例子来说明模式。比如:当客户提出一个新的软件需求的时候,大家经过多个日以继夜的努力,终于通过一个比较不错的软件设计解决了客户的需求,而且这个设计有相对完美的类层次结构并且符合OO的设计原则,大家为此感到开心,颇有成就感。又过了一段时间,客户突然又有一个新的需求,需要在现有的类层次结构里面增加一个新的操作(其实就是一个方法),怎么办?还好,在面向OO设计模式中有一个模式就是为了解决这个问题的,那就是访问者模式,下面让我们好好地了解一下该模式。
二、访问者模式介绍
访问者模式:英文名称--Visitor Pattern;分类--行为型。
2.1、动机(Motivate)
在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作?
2.2、意图(Intent)
表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。——《设计模式》GoF
2.3、结构图(Structure)
2.4、模式的组成
可以看出,在访问者模式的结构图有以下角色:
1)抽象访问者角色(Visitor): 声明一个包括多个访问操作,多个操作针对多个具体节点角色(可以说有多少个具体节点角色就有多少访问操作),使得所有具体访问者必须实现的接口。
2)具体访问者角色(ConcreteVisitor):实现抽象访问者角色中所有声明的接口,也可以说是实现对每个具体节点角色的新的操作。
3)抽象节点角色(Element):声明一个接受操作,接受一个访问者对象作为参数,如果有其它参数,可以在这个“接受操作”里在定义相关的参数。
4)具体节点角色(ConcreteElement):实现抽象元素所规定的接受操作。
5)结构对象角色(ObjectStructure):节点的容器,可以包含多个不同类或接口的容器。
2.5、访问者模式的具体实现
访问者模式在我们现实的编码生活中使用的并不是很多,我就直接贴代码,让大家看看代码的结构吧。今天给大家两个代码实例,实现代码如下:
class Program { /// <summary> /// 抽象图形定义--相当于“抽象节点角色” /// </summary> public abstract class Shape { //画图形 public abstract void Draw(); //外界注入具体访问者 public abstract void Accept(ShapeVisitor visitor); } /// <summary> /// 矩形--相当于“具体节点角色” /// </summary> public sealed class Rectangle : Shape { public override void Draw() { Console.WriteLine("矩形我已经画好了。"); } public override void Accept(ShapeVisitor visitor) { visitor.Visit(this); } } /// <summary> /// 圆形--相当于“具体节点角色” /// </summary> public sealed class Circle : Shape { public override void Draw() { Console.WriteLine("圆形我已经画好了。"); } public override void Accept(ShapeVisitor visitor) { visitor.Visit(this); } } /// <summary> /// 直线--相当于“具体节点角色” /// </summary> public sealed class Line : Shape { public override void Draw() { Console.WriteLine("直线我已经画好了。"); } public override void Accept(ShapeVisitor visitor) { visitor.Visit(this); } } /// <summary> /// 抽象访问者 /// </summary> public abstract class ShapeVisitor { public abstract void Visit(Rectangle shape); public abstract void Visit(Circle shape); public abstract void Visit(Line shape); //这里有一点要说:Visit方法的参数可以写成Shape吗?就是这样Visit(Shape shape)。 //答案是可以,但是ShapeVisitor子类的Visit方法就需要判断当前的Shape是什么类型?是Rectangle类型?还是Circle类型?或者是Line类型? } /// <summary> /// 具体访问者 /// </summary> public sealed class CustomVisitor : ShapeVisitor { //针对Rectangle对象 public override void Visit(Rectangle shape) { Console.WriteLine("针对Rectangle新的操作。"); } //针对Circle对象 public override void Visit(Circle shape) { Console.WriteLine("针对Circle新的操作。"); } //针对Line对象 public override void Visit(Line shape) { Console.WriteLine("针对Line新的操作。"); } } /// <summary> /// 结构对象角色 /// </summary> internal class AppStructure { private readonly ShapeVisitor _visitor; public AppStructure(ShapeVisitor visitor) { _visitor = visitor; } public void Process(Shape shape) { shape.Accept(_visitor); } } static void Main(string[] args) { #region 访问者模式(第一个实例) ShapeVisitor visitor = new CustomVisitor(); AppStructure app = new AppStructure(visitor); Shape shape = new Rectangle(); shape.Draw(); //执行自己的操作 app.Process(shape); //执行新的操作 shape = new Circle(); shape.Draw(); //执行自己的操作 app.Process(shape); //执行新的操作 shape = new Line(); shape.Draw(); //执行自己的操作 app.Process(shape); //执行新的操作 Console.ReadLine(); #endregion } }