其他分享
首页 > 其他分享> > 【设计模式篇】访问者模式(Visitor)

【设计模式篇】访问者模式(Visitor)

作者:互联网

访问者模式

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

先通过结构图,来了解访问者模式

应用场景

我们先看一下访问者模式中都有哪些角色
实际上访问者模式中有三类对象,访问者、元素对象、对象结构,核心要做的事情都是在具体的访问者中进行

访问者模式适用于对象种类相对稳定的场景,它解决的实际上是将对象与作用于对象的行为进行分离解耦,使得在不更改对象结构的前提下,可以更灵活地对作用于对象的行为操作进行更改。

示例应用

场景一:
比如一天有三个重要时刻,分别为早中晚,我们对Harley、Baffett进行调查,观察他们在这些时刻都做了什么事情。

因为早中晚是相对稳定的时刻,我们可以将早中晚三个时刻声明三个元素对象,把Harley、Buffett声明为两个具体访问者对象,然后会在具体访问者对象中描述访问者的具体行为。

示例结构图

Environment:
Visual Studio Code、.Net 6

相关命令:

// 创建项目文件夹
mkdir DesignPattern
// 创建项目文件
dotnet new sln
// 创建访问者控制台文件夹
mkdir DesignPattern.Visitor.Console
// 创建访问者控制台项目
dotnet new console
// 运行项目
dotnet run

代码片段一

public abstract class TimeElement
{
    public TimeSpan Begin { get; set; }
    public TimeSpan End { get; set; }
    public abstract void Accept(Visitor visitor);
}

public class MorningTimeElement : TimeElement
{
    public MorningTimeElement()
    {
        Begin = TimeSpan.FromHours(6);
        End = TimeSpan.FromHours(11);
    }
    public override void Accept(Visitor visitor)
    {
        visitor.Visit(this);
    }
}

public class MorningTimeElement : TimeElement
{
    public MorningTimeElement()
    {
        Begin = TimeSpan.FromHours(6);
        End = TimeSpan.FromHours(11);
    }
    public override void Accept(Visitor visitor)
    {
        visitor.Visit(this);
    }
}

public class AfterNoonElement : TimeElement
{
    public AfterNoonElement()
    {

        Begin = TimeSpan.FromHours(13);
        End = TimeSpan.FromHours(18);
    }
    public override void Accept(Visitor visitor)
    {
        visitor.Visit(this);
    }
}

代码片段二

public abstract class Visitor
{
    public abstract void Visit(MorningTimeElement timeElement);
    public abstract void Visit(NoonTimeElement timeElement);
    public abstract void Visit(AfterNoonElement timeElement);
}

public class HarleyVisitor : Visitor
{
    public override void Visit(MorningTimeElement timeElement)
    {
        System.Console.WriteLine($"Harley 在 {timeElement.Begin:hh\\:mm} 起床,然后开始学习、工作,在 {timeElement.End:hh\\:mm}开始午休");
    }

    public override void Visit(NoonTimeElement timeElement)
    {
        System.Console.WriteLine($"Harley 在 {timeElement.Begin:hh\\:mm} 准备吃午餐,并在{timeElement.End:hh\\:mm}前进行午睡");
    }

    public override void Visit(AfterNoonElement timeElement)
    {
        System.Console.WriteLine($"Harley 在 {timeElement.Begin:hh\\:mm} 开始工作,在 {timeElement.End:hh\\:mm} 下班休息");
    }
}

public class BuffettVisitor : Visitor
{
    public override void Visit(MorningTimeElement timeElement)
    {
        System.Console.WriteLine($"Buffett 在 {timeElement.Begin:hh\\:mm} 还在睡梦中,大约45分钟后起床,然后开始准备开会,在 {timeElement.End:hh\\:mm}开始午休");
    }

    public override void Visit(NoonTimeElement timeElement)
    {
        System.Console.WriteLine($"Buffett 在 {timeElement.Begin:hh\\:mm} 准备吃午餐,并在{timeElement.End:hh\\:mm}前进行准备下午会议");
    }

    public override void Visit(AfterNoonElement timeElement)
    {
        System.Console.WriteLine($"Buffett 在 {timeElement.Begin:hh\\:mm} 开始进行下午会议,在 {timeElement.End:hh\\:mm} 下班休息");
    }
}

代码片段三

public class ObjectStructure
{
    private IList<TimeElement> elements = new List<TimeElement>();

    public void Add(TimeElement element) => elements.Add(element);

    public void Delete(TimeElement element) => elements.Remove(element);

    public void Accept(Visitor visitor)
    {
        foreach (var item in elements)
        {
            item.Accept(visitor);
        }
    }
}

客户端

Console.WriteLine("Hello, Harley!");
Console.OutputEncoding = System.Text.Encoding.UTF8;

var morningElement = new MorningTimeElement();
var noonElement = new NoonTimeElement();
var afterNoonElement = new AfterNoonElement();

var objectStructure = new ObjectStructure();
objectStructure.Add(morningElement);
objectStructure.Add(noonElement);
objectStructure.Add(afterNoonElement);

var buffettVisitor = new BuffettVisitor();
var harleyVisitor = new HarleyVisitor();

System.Console.WriteLine("******buffett visitor");
objectStructure.Accept(buffettVisitor);
System.Console.WriteLine("******harley visitor");
objectStructure.Accept(harleyVisitor);

Console.Read();

在控制台执行dotnet run,结果如下:

总结
访问者模式是行为型设计模式,关注的是对象与行为的分离。适用于对象结构相对稳定,作用于对象结构上的操作又可以独立演化的场景。在对象结构上增加操作就是创建一个具体的访问者对象,并且完全遵循了开闭原则,降低了对象与行为的耦合性,但是它同时也有很大的缺点,不适用于对象结构易于变化的场景,同时违反了依赖倒置原则、迪米特法则。

所以,只有在业务比较合适的场景,才能发挥访问者模式的优势。

优点:

缺点:

References:

《Head First 设计模式》
《大话设计模式》

标签:timeElement,对象,Visitor,void,Visit,设计模式,public,访问者
来源: https://www.cnblogs.com/harley-chang/p/16667973.html