苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper万能框架(V2.3-含.netcore) HttpHelper官方出品,无敌框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 最牛的爬虫类,没有爬不到只有想不到 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 685|回复: 4

[学习心得] C#访问者模式例子

[复制链接]
发表于 2019-1-14 14:57:45 | 显示全部楼层 |阅读模式
一 、  一个实际应用 Visitor  模式的例子

以下的例子演示了 Employee 对象集合允许被不同的 Visitor(IncomeVisitor 与 VacationVisitor)访问其中的内容。

[C#] 纯文本查看 复制代码
// Visitor pattern -- Real World example
using System;
using System.Collections;
// "Visitor"
abstract class Visitor
{
    // Methods
    public abstract void Visit(Element element);
}
// "ConcreteVisitor1"
class IncomeVisitor : Visitor
{
    // Methods
    public override void Visit(Element element)
    {
        Employee employee = ((Employee)element);
        // Provide 10% pay raise
        employee.Income *= 1.10;
        Console.WriteLine("{0}'s new income: {1:C}",
        employee.Name, employee.Income);
    }
}
// "ConcreteVisitor2"
class VacationVisitor : Visitor
{
    public override void Visit(Element element)
    {
        Employee employee = ((Employee)element);
        // Provide 3 extra vacation days
        employee.VacationDays += 3;
        Console.WriteLine("{0}'s new vacation days: {1}",
        employee.Name, employee.VacationDays);
    }
}
// "Element"
abstract class Element
{
    // Methods
    abstract public void Accept(Visitor visitor);
}
// "ConcreteElement"
class Employee : Element
{
    // Fields
    // Constructors
    public Employee(string name, double income,
    int vacationDays)
    {
        Name = name;
        Income = income;
        VacationDays = vacationDays;
    }
    // Properties
    public string Name { get; set; }

    public double Income { get; set; }

    public int VacationDays { get; set; }

    // Methods
    public override void Accept(Visitor visitor)
    {
        visitor.Visit(this);
    }
}
// "ObjectStructure"
class Employees
{
    // Fields
    private readonly ArrayList _employees = new ArrayList();
    // Methods
    public void Attach(Employee employee)
    {
        _employees.Add(employee);
    }
    public void Detach(Employee employee)
    {
        _employees.Remove(employee);
    }
    public void Accept(Visitor visitor)
    {
        foreach (Employee e in _employees)
            e.Accept(visitor);
    }
}
/// <summary>
/// VisitorApp test
/// </summary>
public class VisitorApp
{
    public static void Main(string[] args)
    {
        // Setup employee collection
        Employees e = new Employees();
        e.Attach(new Employee("Hank", 25000.0, 14));
        e.Attach(new Employee("Elly", 35000.0, 16));
        e.Attach(new Employee("Dick", 45000.0, 21));
        // Create two visitors
        IncomeVisitor v1 = new IncomeVisitor();
        VacationVisitor v2 = new VacationVisitor();
        // Employees are visited
        e.Accept(v1);
        e.Accept(v2);
    }
}


二 、  在什么情况下应当使用访问者模式

      有意思的是,在很多情况下不使用设计模式反而会得到一个较好的设计。换言之,每一个设计模式都有其不应当
使用的情况。访问者模式也有其不应当使用的情况,让我们先看一看访问者模式不应当在什么情况下使用。
倾斜的可扩展性

      访问者模式仅应当在被访问的类结构非常稳定的情况下使用。换言之,系统很少出现需要加入新节点的情况。如
果出现需要加入新节点的情况,那么就必须在每一个访问对象里加入一个对应于这个新节点的访问操作,而这是
对一个系统的大规模修改,因而是违背"开一闭"原则的。

访问者模式允许在节点中加入新的方法,相应的仅仅需要在一个新的访问者类中加入此方法,而不需要在每一个
访问者类中都加入此方法。

      显然,访问者模式提供了倾斜的可扩展性设计:方法集合的可扩展性和类集合的不可扩展性。换言之,如果系统
的数据结构是频繁变化的,则不适合使用访问者模式。

"开一闭"原则和对变化的封装

      面向对象的设计原则中最重要的便是所谓的"开一闭"原则。一个软件系统的设计应当尽量做到对扩展开放,对修
改关闭。达到这个原则的途径就是遵循"对变化的封装"的原则。这个原则讲的是在进行软件系统的设计时,应当
设法找出一个软件系统中会变化的部分,将之封装起来。

      很多系统可以按照算法和数据结构分开,也就是说一些对象含有算法,而另一些对象含有数据,接受算法的操作。
如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问
者模式使得算法操作的增加变得容易。

      反过来,如果这样一个系统的数据结构对象易于变化,经常要有新的数据对象增加进来的话,就不适合使用访问
者模式。因为在访问者模式中增加新的节点很困难,要涉及到在抽象访问者和所有的具体访问者中增加新的方法。

三 、  使用访问者模式的优点和缺点

访问者模式有如下的优点:

1. 访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者
模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。

2. 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。

3. 访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属
于不同等级结构的对象。访问者模式可以做到这一点。

4. 积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的
节点对象中。这是有益于系统维护的优点。

访问者模式有如下的缺点:

1. 增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的
具体操作。

2. 破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作
和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使这些状态不再存储在节点对象中,这
也是破坏封装的。





发表于 2019-1-14 15:12:17 | 显示全部楼层
发表于 2019-1-14 15:36:20 | 显示全部楼层
发表于 2019-1-14 19:48:39 | 显示全部楼层
发表于 2019-1-14 20:57:36 | 显示全部楼层
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备17001017号-1)

GMT+8, 2019-12-7 23:05

© 2017-2018

快速回复 返回顶部 返回列表