那些开发中用到的模式——访问者模式

为了尽可能演示出Visitor 设计模式的强大之处,在此举一个开发中的场景
例如 开发A组 负责做log功能,而B组需要A组暴露一个API,可以拿到所有的log。

A组的代码实现可能是如下这样的:

public abstract class OrderLog{
public string Content {get;set;}
public OrderLog(string content){
Content = content;
}

}

public class PlaceOrderLog :OrderLog{
public PlaceOrderLog(string content,string orderedBy):base(content)
{
OrderedBy = orderedBy;
}
public string OrderedBy {get;set;}

}

public class MakePaymentLog :OrderLog{
public MakePaymentLog(string content, string paymentGateway, string payedBy):base(content)
{
PaymentGateway = paymentGateway;
PayedBy = payedBy;
}
public string PaymentGateway {get;set;}
public string PayedBy {get;set;}

}

public class OrderCompleteLog : OrderLog{
public OrderCompleteLog(string content, DateTime completeDate):base(content)
{
OrderCompleteDate = completeDate;
}
public DateTime OrderCompleteDate {get;set;}

}

public class OrderLogger{
public static OrderLogger Do
{
get
{
return new OrderLogger();
}
}

public IEnumerable<OrderLog> GetLogs(){
return new List<OrderLog>{
new PlaceOrderLog("place order log","ordered by"),
new MakePaymentLog("make payment log","paypal", "payedBy"),
new OrderCompleteLog("order complete log",DateTime.Now)
};

}

}

B组用法:

var logs = OrderLogger.Do.GetLogs();

B组新需求来了,需要A组再做一个API,可以把颜色信息加入LOG实体中,比如类型A返回红色,类型B返回绿色
A组有两个选择,再加一个API,还是把这个责任分发回B组,因为显然显示颜色的逻辑B组更熟悉。当然是分发责任,可如何分发,访问者模式来了。

1.在Log基类中添加一行:

public abstract T Visit<T>(ILogVisitor<T> visitor);

2.其他log子类中相应的实现它:

public override T Visit<T>(ILogVisitor<T> visitor){
return visitor.Visit(this);
}

为什么加这个方法?相当于给外界开一个入口,这样它们可以进来,然后把自身的信息传递给它们完成相应逻辑。

3.给B组一个接口(如果没有返回值,可以把T拿掉):

public interface ILogVisitor<T>{
T Visit(PlaceOrderLog log);
T Visit(MakePaymentLog log);
T Visit(OrderCompleteLog log);
}

为什么加这个接口?
1. 外部的访问者实现这个接口,就可以获取每个子类
2. 如果类层次变化,外部可以知道
3. 外部调用不用写大量的switch-case 或 if else臃肿的判断逻辑了

A组工作完成。接下来是B组要做的事情了——实现访问者接口。
实现也许是这样的:

public enum OrderLogColor{Red,Green}

public class OrderLogColorVisitor:ILogVisitor<OrderLogColor>{
public OrderLogColor Visit(PlaceOrderLog log){
return OrderLogColor.Red;
}

public OrderLogColor Visit(MakePaymentLog log){
return OrderLogColor.Green;
}

public OrderLogColor Visit(OrderCompleteLog log){
return OrderLogColor.Green;
}

}

逻辑很简单,对于不同的类型返回不同颜色。接下来就是调用部分:

var logs = OrderLogger.Do.GetLogs();
	////show colors
	var colorVisitor = new OrderLogColorVisitor();
	foreach(var log in logs){
	Console.WriteLine(log.Visit<OrderLogColor>(colorVisitor));
	}

可以看到,拿到一个日志集合后,循环过程只需调用Visit函数,就进入了相应的log类,然后在log类中,调用Visit函数完成Visit逻辑。执行结果:

Red
Green
Green

接下来,B组需要一个新的任务,对不同的日志类型,格式化显示不同的字符串。

于是只需要添加另一个Visitor:

public class OrderLogFormattedVisitor : ILogVisitor <string> {

public string Visit(PlaceOrderLog log){
return "this is place order log formatted information ";
}

public string Visit(MakePaymentLog log){
return "this is make payment log formatted information ";
}

public string Visit(OrderCompleteLog log){
return "this is order complete log formatted information ";
}

}

调用:

var logs = OrderLogger.Do.GetLogs();
var formatVisitor = new OrderLogFormattedVisitor();
	foreach(var log in logs){
	Console.WriteLine(log.Visit<string>(formatVisitor));
	}

看出访问者模式的作用了吗?它把职责隔离的同时,有效的封装了变化。在以上例子中,A组只负责做LOG API,而B组负责拿到LOG后的事情。 在开发中会经常遇到相互调用的情况,每当这个时候,首先考虑职责分配,用接口隔离工作,决定调用的入口。这便是访问者模式的强大之处。

以下是完整的代码:

void Main()
{
	var logs = OrderLogger.Do.GetLogs();
	////show colors
	var colorVisitor = new OrderLogColorVisitor();
	foreach(var log in logs){
	Console.WriteLine(log.Visit<OrderLogColor>(colorVisitor));
	}
	////show formatted logs
	var formatVisitor = new OrderLogFormattedVisitor();
	foreach(var log in logs){
	Console.WriteLine(log.Visit<string>(formatVisitor));
	}
}

////team A job
public abstract class OrderLog{
public string Content {get;set;}
public OrderLog(string content){
Content = content;
}

public abstract T Visit<T>(ILogVisitor<T> visitor);

}

public class PlaceOrderLog :OrderLog{
public PlaceOrderLog(string content,string orderedBy):base(content)
{
OrderedBy = orderedBy;
}
public string OrderedBy {get;set;}

public override T Visit<T>(ILogVisitor<T> visitor){
return visitor.Visit(this);
}

}

public class MakePaymentLog :OrderLog{
public MakePaymentLog(string content, string paymentGateway, string payedBy):base(content)
{
PaymentGateway = paymentGateway;
PayedBy = payedBy;
}
public string PaymentGateway {get;set;}
public string PayedBy {get;set;}

public override T Visit<T>(ILogVisitor<T> visitor){
return visitor.Visit(this);
}
}

public class OrderCompleteLog : OrderLog{
public OrderCompleteLog(string content, DateTime completeDate):base(content)
{
OrderCompleteDate = completeDate;
}
public DateTime OrderCompleteDate {get;set;}

public override T Visit<T>(ILogVisitor<T> visitor){
return visitor.Visit(this);
}

}

public class OrderLogger{
public static OrderLogger Do
{
get
{
return new OrderLogger();
}
}

public IEnumerable<OrderLog> GetLogs(){
return new List<OrderLog>{
new PlaceOrderLog("place order log","ordered by"),
new MakePaymentLog("make payment log","paypal", "payedBy"),
new OrderCompleteLog("order complete log",DateTime.Now)
};

}

}

////now team B want a API , return different log color based on different type
////team A give team B a visitor interface , ask them to implement

public interface ILogVisitor<T>{
T Visit(PlaceOrderLog log);
T Visit(MakePaymentLog log);
T Visit(OrderCompleteLog log);
}

////team B come out with the implementations

public enum OrderLogColor{Red,Green}

public class OrderLogColorVisitor:ILogVisitor<OrderLogColor>{
public OrderLogColor Visit(PlaceOrderLog log){
return OrderLogColor.Red;
}

public OrderLogColor Visit(MakePaymentLog log){
return OrderLogColor.Green;
}

public OrderLogColor Visit(OrderCompleteLog log){
return OrderLogColor.Green;
}

}

////in future
////if team B want more , just implement the ILogVisitor interface
////for example : formatted log

public class OrderLogFormattedVisitor : ILogVisitor <string> {

public string Visit(PlaceOrderLog log){
return "this is place order log formatted information ";
}

public string Visit(MakePaymentLog log){
return "this is make payment log formatted information ";
}

public string Visit(OrderCompleteLog log){
return "this is order complete log formatted information ";
}

}

////whats next
////whenever team B want , he just add more visitor to accept different log types returned from teamA
时间: 2024-10-12 09:48:33

那些开发中用到的模式——访问者模式的相关文章

22 行为型模式-----访问者模式

模式动机(Visitor Pattern):访问者模式用于操作存储于某个集合中的各元素,使得可以在不改变元素类的前提下定义作用于这些元素的新操作. 之所以使用访问者类,是因为存储于某个集合中的元素可能具有不同的特性,而不同的访问者可能更看重某一方面的特性,如果让集合类本身承担访问操作,那么对于不同的访问操作,必须对应地定义不同的方法,不仅使得类变得极其庞大,而且难以扩展. 利用访问者模式可以解决上述问题.其将集合中元素的操作封装在一个Visitor继承体系中,不同的Visitor实现类可以满足不

【GOF23设计模式】解释器模式 &amp; 访问者模式

来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_解释器模式.访问者模式.数学表达式动态解析库式 1.解释器模式Interpreter  2.访问者模式Visitor 

Android学习之访问者模式详解

本文和大家分享的主要是android设计模式中的访问者模式相关内容,一起来看看吧,希望对大家学习android有所帮助. 访问者模式 访问者模式属于行为模式. 访问者模式中属于相对比较复杂的一类,它会在A中让B访问,而实际在B中实际调用的是A的方法. class A { public void method1(){ System.out.println("AAAAAA"); } public void method2(B b){ b.showA(this); } } class B {

9.泡妞与设计模式(10) 访问者模式

VISITOR 访问者模式 访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变.访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化.访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类.访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中.当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的

设计模式-行为型模式-策略模式

策略模式 在实际工作中我用到了策略模式,但为什么要有环境角色呢? 这里我贴上英文对含义的介绍, The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. 然后看看这种设计模式的组成, 一般的,策略模式

设计模式----访问者模式

?定义:表示一个作用于某对象结构中的歌元素的操作,可以使你在不改变个元素的类的前提下定义作用于这些元素的操作. 当需要扩展一个已有类的层次结构时,我们一般只需要简单增加一些方法来扩展的行为,会出现已有对象和需要扩展的行为不一致的情况,这种情况下不修改层次结构中的类就无法扩展其行为.访问者模式可以解决这个问题. 1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口.该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定

设计模式之禅之设计模式-访问者模式

一:访问者模式定义        --->封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 二:访问者模式角色● Visitor——抽象访问者        抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的.● ConcreteVisitor——具体访问者        它影响访问者访问到一个类后该怎么干,要做什么事情.● Element——抽象元素        接口或者抽象类,声

24种设计模式--访问者模式【Visitor Pattern】

今天天气不错,绝对是晴空万里,骄阳似火呀,好,我们今天来讲访问者模式,我们在前面讲了组合模式和迭代器模式,通过组合模式我们能够把一个公司的人员组织机构树搭建起来,给管理带来非常大的便利,通过迭代器模式我们可以把每一个员工都遍历一遍,看看是不是有“人去世了还在领退休金”, “拿高工资而不干活的尸位素餐”等情况,那我们今天的要讲访问者模式是做什么用的呢? 我们公司有七百多技术人员,分布在全国各地,组织架构你在组合模式中也看到了,很常见的家长领导型模式,每个技术人员的岗位都是固定的,你在组织机构的那棵

10 行为型模式之 - 访问者模式

访问者模式介绍:访问者模式是一种将数据操作与数据结构分离的设计模式,它是<设计模式>中23种设计模式中最复杂的一个,但是它的使用频率并不高,正如<设计模式>的作者GOF对访问者模式的描述:大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是真地需要它了. 访问者模式的基本想法是,软件系统中拥有一个由许多对象构成的,比较稳定的对象结构,这些对象的类都拥有一个accept方法,用来接受访问者对象的访问.访问者是一个接口,它拥有一个visit方法,从而使访问者得以处