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

WeN*_*ers 7 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;
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

我可能有错误的模式,它看起来像上面代码中的访问者模式.所以我认为我的比较成立了.

有些代码,我会说扩展方法看起来像访问者模式.

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Sco*_*ski 9

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

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

在任何情况下,扩展方法在非虚拟方法有用的任何地方都是有用的,并且您不需要拥有类型来定义扩展方法.

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

模板方法模式通过向对象树中的每个类型添加操作的虚方法来工作,其中"聚合节点"在其包含的节点上调用方法.

示例可以是表达式树的"打印"方法.

public class Node
{
   abstract void print();
}

public class AddExpression : Node {
    Node Left;
    Node Right;

    virtual void print() {
        Left.Print();
        Console.WriteLine("+");
        Right.Print();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

访问者模式将模板方法概括为一个名为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

如果两者同等变化,那么您的决定应基于平衡:

  1. 清晰度(模板方法更容易理解,并避免双重调度的开销).
  2. 重用(访问者将常见的遍历代码放在一个地方).

  • 迭代器模式是一种设计模式...... for循环是实现它的一种方式的机制...... (5认同)
  • 咦?扩展方法不是设计模式.它比dedign模式更低.这只是一种方法."for循环"的方式与模式不同. (2认同)

tst*_*ter 0

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

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

  • @WeeNeedAnswers,扩展方法只不过是静态方法。任何可以使用扩展方法完成的“模式”都可以使用静态方法完成。此外,扩展方法是一种语言特征,而不是一种模式。设计模式是常见问题的通用解决方案,并且(大部分)与语言无关。扩展方法只是用一种特定语言调用静态方法的不同方式。我的回答很简短,充分反映出问题缺乏重点。如果我问“请比较一下汽车和手机”,我不会想到“它们是不同的” (4认同)
  • 它们是一种设计模式,只是语法糖隐藏了它们的真正含义。 (2认同)
  • 我对扩展确实形成一种模式这一事实投了反对票。它作用于传入的对象。模式会不断重复,这就是模式。您可以一遍又一遍地重复使用该模式。事实上,环境很好地包裹了它,使像 Linq 这样可爱的语言看起来和感觉起来像一种 SQL 类型语言,但这并不能阻止扩展方法是一种模式的事实。如果您诚实地将扩展方法视为“语法糖”,那么我恳求您再次查看它们并重新评估您的观点。 (2认同)
  • 我还对答案的简洁性投了反对票,并且在没有考虑所提出的问题的情况下就给出了意见。这让人不禁要问,这样做的目的是否只是为了听起来很聪明,而根本不是为了回答问题。保持神秘和简洁比保持礼貌、诗意和有某种风格更容易。关心需要时间,不关心也需要几分钟。 (2认同)