责任链模式,Chain ofResponsibility,就是说有一系列的处理过程,这些处理过程有先后顺序,就跟ASP.NET Framework的Pipeline事件一样,挨个对request进行处理。
下面我们用一个简单的例子来说说这种设计模式。我们假设一种场景,有一条message(字符串)要从A传送到B,但是这个过程中会有多个处理过程,比如说过滤掉敏感字符("government"),并且把"haha"替换成笑脸"-^^-".
1.我们可以设定一个IFilter接口,然后让所有的处理过程都实现这个接口。然后我们设置一个Filter的集合,把所有的Filter都放到这个集合里边来。
class Program
{
static void Main(string[] args)
{
Message message = new Message()
{
ID = 1,
Content = "Our government is good. haha"
};
FilterChain chain = new FilterChain();
chain.AddFilter(new SensitiveWordsFilter());
chain.AddFilter(new EmotionFaceFilter());
chain.doFilter(message);
Console.WriteLine(message.Content);
Console.ReadLine();
}
}
public class Message
{
public int ID { get; set; }
public String Content { get; set; }
}
public interface IFilter
{
void doFilter(Message message);
}
public class SensitiveWordsFilter : IFilter
{
public void doFilter(Message message)
{
message.Content = message.Content.Replace("government", "***");
}
}
public class EmotionFaceFilter : IFilter
{
public void doFilter(Message message)
{
message.Content = message.Content.Replace("haha", "-^^-");
}
}
public class FilterChain
{
private readonly IList<IFilter> list;
public void AddFilter(IFilter filter)
{
this.list.Add(filter);
}
public FilterChain()
{
this.list = new List<IFilter>();
}
public void doFilter(Message message)
{
foreach (var filter in list)
{
filter.doFilter(message);
}
}
}
这段代码的运行结果如下图所示,一切按计划进行。
2.此时,我们的需求不仅仅局限在往一个Chain集合中加入Filter,现在我们需要向一个Chain集合中加入另一个Chain集合。这时候我们怎么办?我们可以让FilterChain也实现IFitler接口,那么我们就可以直接调用FilterChain的Add方法了。
class Program
{
static void Main(string[] args)
{
Message message = new Message()
{
ID = 1,
Content = "Our government is good. haha five"
};
FilterChain chain = new FilterChain();
chain.AddFilter(new SensitiveWordsFilter());
chain.AddFilter(new EmotionFaceFilter());
FilterChain chain2 = new FilterChain();
chain2.AddFilter(new NumberFilter());
chain.AddFilter(chain2);
chain.doFilter(message);
Console.WriteLine(message.Content);
Console.ReadLine();
}
}
public class Message
{
public int ID { get; set; }
public String Content { get; set; }
}
public interface IFilter
{
void doFilter(Message message);
}
public class SensitiveWordsFilter : IFilter
{
public void doFilter(Message message)
{
message.Content = message.Content.Replace("government", "***");
}
}
public class EmotionFaceFilter : IFilter
{
public void doFilter(Message message)
{
message.Content = message.Content.Replace("haha", "-^^-");
}
}
public class NumberFilter : IFilter
{
public void doFilter(Message message)
{
message.Content = message.Content.Replace("five", "5");
}
}
public class FilterChain : IFilter
{
private readonly IList<IFilter> list;
public void AddFilter(IFilter filter)
{
this.list.Add(filter);
}
public FilterChain()
{
this.list = new List<IFilter>();
}
public void doFilter(Message message)
{
foreach (var filter in list)
{
filter.doFilter(message);
}
}
}
运行结果如下图所示。
对于第2种方式总结一下,就是如何能够让一个责任链加入到另一个责任链中。当然我们可以依次遍历这个责任链集合,然后一个个的加到另外的责任链中。但这种方法很繁琐。最简单方法是这样做,我们让FilterChain也实现IFilter接口,把它看成一个大个的Filter,然后FilterChain中进行处理的方法要与NumberFilter,SensitiveWordsFilter等这些具体的Filter中的方法同名,并且都是实现IFilter接口中的方法。
另外,还有一种链式编程的技巧。在FilterChain中,我们让每次AddFilter之后,都让其返回自身。这样我们所以的Add方法都能在一行代码中完成。
public FilterChain AddFilter(IFilter filter)
{
this.list.Add(filter);
return this;
}
在使用的时候,就可以这样。
FilterChain chain = new FilterChain();chain.AddFilter(new SensitiveWordsFilter()).AddFilter(new EmotionFaceFilter());
3.现在我们的需求又变了。我们希望我们的责任链处理器能向ASP.NET Pipeline那样,去的时候按先后顺序处理Request,回来的时候按照顺序处理Repsone.
class Program
{
static void Main(string[] args)
{
Request request = new Request()
{
ID = 1,
Content = "This is the orginal request string. "
};
Response response = new Response()
{
ID = 1,
Content = "This is the orginal response string. "
};
FilterChain chain = new FilterChain();
chain.AddFilter(new SensitiveWordsFilter())
.AddFilter(new EmotionFaceFilter());
FilterChain chain2 = new FilterChain();
chain2.AddFilter(new NumberFilter());
chain.AddFilter(chain2);
chain.doFilter(request, response);
Console.WriteLine(request.Content);
Console.WriteLine();
Console.WriteLine(response.Content);
Console.ReadLine();
}
}
public class Request
{
public int ID { get; set; }
public String Content { get; set; }
}
public class Response
{
public int ID { get; set; }
public String Content { get; set; }
}
public interface IFilter
{
void doFilter(Request request, Response response);
}
public class SensitiveWordsFilter : IFilter
{
public void doFilter(Request request, Response response)
{
request.Content = request.Content + " --SensitiveFilter In-- ";
response.Content = response.Content + " --SensitiveFilter Out-- ";
}
}
public class EmotionFaceFilter : IFilter
{
public void doFilter(Request request, Response response)
{
request.Content = request.Content + " --EmotionFaceFilter In-- ";
response.Content = response.Content + " --EmotionFaceFilter Out-- ";
}
}
public class NumberFilter : IFilter
{
public void doFilter(Request request, Response response)
{
request.Content = request.Content + " --NumberFilter In-- ";
response.Content = response.Content + " --NumberFilter Out-- ";
}
}
public class FilterChain : IFilter
{
private readonly IList<IFilter> list;
public FilterChain AddFilter(IFilter filter)
{
this.list.Add(filter);
return this;
}
public FilterChain()
{
this.list = new List<IFilter>();
}
public void doFilter(Request request, Response response)
{
foreach (var filter in list)
{
filter.doFilter(request, response);
}
}
}
运行结果如下图所示。
但是这不太符合要求。因为进去的时候SensitiveFilter是第一个进行处理的,那么response出来的时候,这个应该是最后一个进行处理才对。
我们可以在FilterChain集合中设置一个变量index,然后一层层的调用。具体代码如下。
internal class Program
{
private static void Main(string[] args)
{
Request request = new Request()
{
ID = 1,
Content = "This is the orginal request string. "
};
Response response = new Response()
{
ID = 1,
Content = "This is the orginal response string. "
};
FilterChain chain = new FilterChain();
chain.AddFilter(new SensitiveWordsFilter())
.AddFilter(new EmotionFaceFilter());
FilterChain chain2 = new FilterChain();
chain2.AddFilter(new NumberFilter());
chain.AddFilter(chain2);
chain.doFilter(request, response, chain);
Console.WriteLine(request.Content);
Console.WriteLine();
Console.WriteLine(response.Content);
Console.ReadLine();
}
}
public class Request
{
public int ID { get; set; }
public String Content { get; set; }
}
public class Response
{
public int ID { get; set; }
public String Content { get; set; }
}
public interface IFilter
{
void doFilter(Request request, Response response, FilterChain chain);
}
public class SensitiveWordsFilter : IFilter
{
public void doFilter(Request request, Response response, FilterChain chain)
{
request.Content = request.Content + " --SensitiveFilter In-- ";
chain.doFilter(request, response, chain);
response.Content = response.Content + " --SensitiveFilter Out-- ";
}
}
public class EmotionFaceFilter : IFilter
{
public void doFilter(Request request, Response response, FilterChain chain)
{
request.Content = request.Content + " --EmotionFaceFilter In-- ";
chain.doFilter(request, response, chain);
response.Content = response.Content + " --EmotionFaceFilter Out-- ";
}
}
public class NumberFilter : IFilter
{
public void doFilter(Request request, Response response, FilterChain chain)
{
request.Content = request.Content + " --NumberFilter In-- ";
chain.doFilter(request, response, chain);
response.Content = response.Content + " --NumberFilter Out-- ";
}
}
public class FilterChain : IFilter
{
private readonly IList<IFilter> list;
private int index = 0;
public FilterChain AddFilter(IFilter filter)
{
this.list.Add(filter);
return this;
}
public FilterChain()
{
this.list = new List<IFilter>();
}
public void doFilter(Request request, Response response, FilterChain chain)
{
if (index == list.Count)
{
return;
}
IFilter filter = list[index];
index++;
filter.doFilter(request, response, chain);
}
}
运行结果如图。符合最终的要求。
综合来讲,责任链模式,就是对于同一个对象进行有序的先后处理的一些工具类的集合。本文文字比较简单,但是代码很详细,希望大家能够从分析代码中有些收获。