扩展方法(类)或访问者模式

本文关键字:访问者 模式 方法 扩展 | 更新日期: 2023-09-27 18:04:22

在进行良好的设计时,您会选择扩展方法还是访问者模式?

哪个更容易设计,什么时候应该在访问者模式上使用扩展方法,反之亦然?

在访问者类上使用扩展方法,除了语法上的好处来提高程序的可读性之外,还有什么好的正当理由吗?

您将如何设计一个包含扩展方法的系统,您会在UML图中对它们进行分类吗?

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }   
}

我可能有错误的模式,它看起来像上面代码中的访问者模式。所以我认为我的比较站得住脚。

一些代码,我想说扩展方法看起来像一个访问者模式。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    #region Interfaces
    public interface IFred
    {
        string Data
        {
            get;
            set;
        }        
        string doSomething();
    }

    public interface IBob
    {
        string Data
        {
            get;
            set;
        }
    }
    #endregion
    #region fred stuff
    public partial class Fred : IFred
    {
        public string doSomething()
        {
            return this.Data + " is really cool";
        }
        public string Value()
        {
            throw new NotImplementedException();
        }
    }
    public partial class Fred
    {
        public string Data
        {
            get;
            set;
        }
    }
    #endregion

    #region bob stuff
    public class BobData : IBob
    {
        public string Data
        {
            get;
            set;
        }
    }
    public class BobData2 : IBob
    {
        private string pData;
        public string Data
        {
            get
            {
                return pData + " and then some!";
            }
            set
            {
                pData = value;
            }
        }
    }
    public class BobVisitor
    {
        public string dosomething(IBob bobData)
        {
            Console.WriteLine(bobData.Data);
            return "ok";
        }
        public string dosomethingOnlyToBob(BobData bobData)
        {
            Console.WriteLine("hello bob version 1");
            return "ok";
        }

        public string dosomethingOnlyToBob2(BobData2 bobData)
        {
            Console.WriteLine("hello bob version 2");
            return "ok";
        }
    }
    #endregion

    public static class Visitor
    {
        public static string visit(this IBob bobObj)
        {
            Console.WriteLine(bobObj.Data);
            return "ok";
        }
        public static string visit(this IFred fredObj)
        {
            Console.WriteLine(fredObj.Data);
            return "ok";
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //Another way of abstracting methods from data, using Partial Classes.
            var fredObj = new Fred();
            fredObj.Data = "fred data";
            fredObj.doSomething();

            //Create the bob classes version 1 and 2
            var bobObj = new BobData();
            bobObj.Data = "bob data";
            var bob2Obj = new BobData2();
            bob2Obj.Data = "bob 2 data";

            //using the bobVisitor Class
            var bobVisitor = new BobVisitor();
            bobVisitor.dosomething(bobObj);
            bobVisitor.dosomething(bob2Obj);
            bobVisitor.dosomethingOnlyToBob(bobObj);
            bobVisitor.dosomethingOnlyToBob2(bob2Obj);

            //using the extension methods in the extension class
            bobObj.visit();
            fredObj.visit();
            Console.Read();
        }
    }
}

扩展方法(类)或访问者模式

您可能应该比较访问者模式和模板方法模式,因为这是您可以比较和对比的两件事。

比较访问者模式和扩展方法就像比较汽车和自行车的链轮。

在任何情况下,扩展方法在非虚方法有用的地方都是有用的,附带的好处是您不需要拥有类型来定义扩展方法。

模板方法和访问者模式都是旨在对对象树进行操作的设计模式。两者的"经典"定义都要求在对象树中的每个"节点类型"中都有一个虚方法。但是,如果有必要,可以使用非虚拟方法来实现这两种方法。有一些限制,比如访问私有成员和受保护成员,但忽略这一点,这两种模式都可以通过扩展方法实现。

模板方法模式的工作方式是为对象树中的每个类型的操作添加一个虚拟方法,通过"聚合节点"调用它们所包含的节点上的方法。

可以是表达式树的"print"方法。

public class Node
{
   abstract void print();
}
public class AddExpression : Node {
    Node Left;
    Node Right;
    virtual void print() {
        Left.Print();
        Console.WriteLine("+");
        Right.Print();
    }
}

这有一个主要的好处,因为添加新的节点类型只需要增量的工作。只需要更改新类型。然而,它有一个缺点,即添加新操作需要编辑每一个类型。

访问者模式将模板方法泛化为一个名为accept的方法,该方法接受访问者对象作为参数。它看起来像:

interface Visitor {
    void VisitAdd(AddExpression e);
    void VisitSubtract(SubtractExpression e);
}
abstract class Node {
    abstract void Accept(Visitor v);
}
class AddExpression : Node {
    //...
    virtual void Accept(Visitor v) {
        Left.Accept(v);
        v.VisitAdd(this);
        Right.Accept(v);
    }
}

这有相反的权衡。添加新操作只需要编写一个新类,但添加新类型需要编辑每个操作。

经典的建议是在操作(相对固定)但可以频繁添加新对象类型时使用模板方法。同样,当对象类型固定时,应该使用访问者,但可以经常添加新操作,

如果两者变化相等,那么你的决定应该基于平衡:

  1. 清晰(模板方法更容易理解,避免了双重调度的开销)。
  2. 重用(访问者将公共遍历代码考虑到一个地方)。

扩展方法不是模式。它们只是一些使代码更容易阅读的语言语法。

访问者模式是完全不同的。我真的不知道你为什么要比较这两个