责任链模式

前言

不知道各位有没有看过在下写的过滤器模式文章,这篇文章主要是用责任链模式去重构之前文章中组合过滤器实现的方式,来讲解责任链模式的优点。

1.之前过滤器的缺点 

建议没有看过如何实现组合过滤器的人去看一下,主要去关注一下ToMergeFilter函数是如何实现的,传送门链接:

https://blog.csdn.net/m0_37920739/article/details/104377144

不知道各位是不是发现那里怪了,简直是菜鸡写的代码(虽然在下确实是菜鸡,但是我是为了这篇文章埋下伏笔,不知道各位看官是否相信,手动滑稽🙃),首先把局部代码放出来,然后分析一下问题到底出在那里。

        public override List<T> ToFilter<T, T1>(List<T> dataSet, T1 condition)    //单条件过滤
        {
            List<T> tmp = new List<T>();
            foreach (T data in dataSet)
            {
                if (CompareFun.Invoke(data, condition))
                    tmp.Add(data);
            }
            return tmp;
        }
 
        public List<T> ToMergeFilter<T, T1>(List<IFilter> filterSet, List<T> dataSet, T1 condition)  //组合过滤
        {
            List<T> tmp = dataSet;
            foreach (IFilter filter in filterSet)
            {
                tmp = filter.ToFilter(tmp, condition);
            }
            return tmp;
        }

我们调用ToMergeFilter函数时,调用了ToFilter去过滤出层层数据,看似没有问题,有问题的代码是ToFilter里的List<T> tmp = new List<T>();,调用一次过滤器就new一个列表,你可能会想平时用C#根本不用垃圾释放啊,其实高级语言都有GC机制,去自动帮你释放不必要的内存数据,所以这样明显会增加GC压力。我们是祖国美好的花朵这么可以莫名其妙就去增加GC的压力呢,如果还不明白为何会增加GC压力,下面将给出示意图:

这个缺点还是可以被弥补的,就是不要new列表去过滤出数据,而是使用Remove的方式层层过滤出数据。但是使用责任链可以把ToMergeFilter函数去掉,用ToFilter函数就是实现单个或者多个条件的过滤,其实你发现单个条件和多个条件过滤本质是一样的,使用责任链让它们更加协调和各司其职,其实在IFilter抽象类里没有定义组合过滤的函数,是因为感觉这个组合过滤函数其实和过滤器类本身是没有任何关系的。

2.责任链模式实现过滤链

接下来我们可以去重写之前的组合过滤器。用责任链模式会形成一个过滤链,就是一个过滤器包含着另外一个过滤器,这样层层过滤下去实现过滤链的效果,具体代码如下:

    public abstract class IFilter
    {
        protected readonly IFilter nextFilter;
        protected object condition;
        protected Func<object, object, bool> CompareFun;

        protected IFilter(Func<object, object, bool> CompareFun, object condition, IFilter nextFilter = null)
        {
            this.nextFilter = nextFilter;
            this.CompareFun = CompareFun;
            this.condition = condition;
        }

        public abstract List<T> ToFilter<T>(List<T> dataSet);
    }

    public class FilterFactory : IFilter
    {
        public FilterFactory(Func<object, object, bool> CompareFun,object condition, IFilter nextFilter = null) 
            : base(CompareFun, condition, nextFilter)
        {
            
        }

        public override List<T> ToFilter<T>(List<T> dataSet)
        {
            for (int i = dataSet.Count - 1; i >= 0; --i)
            {
                if (!CompareFun.Invoke(dataSet[i], condition))
                    dataSet.Remove(dataSet[i]);
            }

            if (null != nextFilter)
                nextFilter.ToFilter(dataSet);
            
            return dataSet;
        }
    }

然后尝试一下调用过滤链会不会出现问题,调用的具体代码如下:

            List<People> Humans = new List<People>();
            Humans.Add(new People("Robert", 19));
            Humans.Add(new People("John", 20));
            Humans.Add(new People("Laura", 51));
            Humans.Add(new People("John", 16));
            Humans.Add(new People("John", 30));
            Humans.Add(new People("Bobby", 9));

            FilterFactory ageFilter= new FilterFactory(delegate (object data, object condition)
            {
                return ((People)data).age > (int)condition;
            }, 18);
            FilterFactory name_ageFilter = new FilterFactory(delegate (object data, object condition)
            {
                return ((People)data).name.Equals(condition.ToString());
            }, "John",ageFilter);

            List<People> tmPeoples = name_ageFilter.ToFilter(Humans);

是不是发现了责任链模式很多优秀的地方,比如你可以随意组合想要的过滤方案(创建不同的过滤链),简直不要太优秀,比起之前使用传递过滤器列表实现组合过滤强太多了。

3.责任链必须用递归?

本来是没有小节三分析的,但是发布文章之后,无意发现一个博主写的文章说责任链不必使用递归去实现(他说网上大部分代码都是递归实现是一个误区...)。首先我完全不赞同这位博主的想法,并且分析为什么责任链无法用循环去替换递归。虽然没有给博主留言,还是希望博主有朝一日发现此文章,首先思考循环去实现责任链是原来的效果吗?大概代码段如下:

            List<IFilter> Filters = new List<IFilter>();
            List<People> Humans = new List<People>();
            Humans.Add(new People("Robert", 19));
            Humans.Add(new People("John", 20));
            Humans.Add(new People("Laura", 51));
            Humans.Add(new People("John", 16));
            Humans.Add(new People("John", 30));
            Humans.Add(new People("Bobby", 9));

            FilterFactory ageFilter= new FilterFactory(delegate (object data, object condition)
            {
                return ((People)data).age > (int)condition;
            }, 18);
            FilterFactory nameFilter = new FilterFactory(delegate (object data, object condition)
            {
                return ((People)data).name.Equals(condition.ToString());
            }, "John");

            Filters.Add(ageFilter);
            Filters.Add(nameFilter);
            foreach (IFilter filter in Filters)
                Humans = Filters.ToFilter(Humans);

就是把对象放到列表里,用这个方法去表示责任链 。想一下责任链的定义是什么?责任链是让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链把请求的数据传递下去,直到遇到递归弹栈的条件循环如何去实现把参数传递下去,并且这么判断对象是否需要响应此请求还有请求数据的关联性,循环实现的对象之前是没有任何关联的,难道用临时变量去存储返回值然后传递给下一个对象?递归明明有这个特性,为什么要花里胡哨的循环去实现?(就算实现出的效果可能达到类似,难道没有感觉蹩脚嘛...)虽然递归确实没有循环快,而且有可能出现栈溢出,因为没有把弹栈条件写好,但是责任链到链底部是百分百弹栈的,责任链示意图如下:

总结

1.责任链的优缺点

优点:1、简化了对象,使得对象不需要知道链子的结构,只关注自身的功能。 2、增强给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

缺点: 1、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成死递归。 2、可能不容易观察运行时的特征,有碍于除错。

2.责任链的使用场景

1.有多个对象负责同一个请求,具体哪个对象处理该请求由运行时刻自动确定。

2.Tomcat 过滤器中的责任链模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值