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

时间:2011-08-04 02:45:22

标签: c# design-patterns

在设置好的设计时,您会选择哪种扩展方法或访客模式?

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

除了语法糖以帮助程序可读性之外,是否有任何合理的理由在访问者类上使用扩展方法?

您如何为包含扩展方法的系统进行设计,是否可以在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();
        }
    }
}

2 个答案:

答案 0 :(得分:8)

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

将访客模式与扩展方法进行比较就像将汽车与自行车链轮进行比较一样。

在任何情况下,扩展方法在非虚拟方法有用的任何地方都很有用,还有额外的好处,你不需要拥有类型来定义扩展方法。

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

模板方法模式的工作原理是为对象树中的每个类型添加操作的虚方法,“聚合节点”调用其包含节点上的方法。

示例可能是表达式树的“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. 重用(访问者将常用遍历代码放在一个地方)。

答案 1 :(得分:0)

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

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