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)
您可能应该将访问者模式与模板方法模式进行比较,因为这些是您可以比较和对比的两件事.
将访客模式与扩展方法进行比较就像将汽车与自行车链轮进行比较一样.
在任何情况下,扩展方法在非虚拟方法有用的任何地方都是有用的,并且您不需要拥有类型来定义扩展方法.
模板方法和访问者模式都是旨在操作对象树的设计模式.两者的"经典"定义需要对象树中每个"节点类型"中的虚方法.但是,如果需要,可以使用非虚拟方法实现这两种方法.存在一些限制,例如访问私有成员和受保护成员,但忽略这一点,可以使用扩展方法实现任一模式.
模板方法模式通过向对象树中的每个类型添加操作的虚方法来工作,其中"聚合节点"在其包含的节点上调用方法.
示例可以是表达式树的"打印"方法.
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)
这有相反的权衡.添加新操作只需要编写一个新类,但添加新类型需要编辑每个操作.
经典的建议是在操作(相对固定)时使用模板方法,但可以经常添加新的对象类型.同样,当键入的对象被修复时,应该使用访问者,但是可以经常添加新操作,
如果两者同等变化,那么您的决定应基于平衡:
扩展方法不是一种模式。它们只是一些使代码更易于阅读的语言语法。
访客模式是一个完全不同的野兽。我真的不知道你为什么要比较两者。