title author date CreateTime categories
C# 设计模式 责任链
lindexi
2019-09-02 12:57:37 +0800
2018-2-13 17:23:3 +0800
C#

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。《JAVA与模式》

我们在 C# 也可以使用责任链。

首先我们需要一个接口IHandle接受我们的责任,在里面,最简单的责任链只有 Successor 和 Request AddSuccessor ,请看代码

    public interface IHandle
{
IHandle Successor
{
set;
get;
} void Request(string str); void AddSuccessor(IHandle successor);
}

责任链的下一个责任接受:Successor

处理责任:Request

添加处理责任的下一个:AddSuccessor

然后我们需要一个实际处理类,这个类集成接口IHandle。可以看到我的接口IHandle 只是处理字符串,其实我们可以处理很多的,但是为了简单,我们就先写字符串。

假如我们是员工,发起的请求是叫老板加工资,那么开始决定工资还不是他,需要经过主管、HR、然后是老板,他们组成了一个责任链。

首先我们定义员工,他可以发送出责任需要让我们的具体处理者处理,但是我们这时看到了主管等其实有重复的,如果主管不同意处理,那么就没必要进行HR同意,所以我们的IHandleAreHandle是不是被处理,因为无论是不是被处理还是要传给下一个,他需要决定这个处理我要不要继续,如果我们的员工提出要求,主管看他不爽,每次都不给他提工资,而我们HR也因为主管处理了,他就不接受,那么这样,员工就得不到提工资,为了解决,我们让HR也要接收到,也就是不管如何都把这个传到下一层,当然这样就需要传下一个AreHandle。如果觉得不需要,那么就不用传下。

另一个,我们不知道我们什么时候实现主管、什么时候实现HR,我们责任链的位置重要,因为如果主管处理了,HR就可以不处理,那么我们需要顺序,一般在添加那里加上权限,这里写Access。我们在添加具体处理,一般判断我们的下一个处理是否存在,如果不存在,直接添加输入参数下一个处理,如果存在,判断权限大小,如果比他大就代换他,如果比他小,就给下一个处理。

        public void AddSuccessor(IHandle successor)
{
if (Successor == null)
{
Successor = successor;
}
else
{
if (successor.Access > Successor.Access)
{
var temp = Successor;
Successor = successor;
successor.Successor = temp;
}
else
{
Successor.AddSuccessor(successor);
}
}
}

我们发现如果把具体处理写为一个类,然后实现,这样每次使用函数Request都用成员,这样不太好,因为我们有功能扩展,所以我们把ConcreteHandler写为抽象,然后继承,写出主管等的类。

    public class GHandle : ConcreteHandler
{
public override void Request(string str)
{
NotifyProperty.Reminder?.Invoke("经理处理"+str);
Successor?.Request(str);
}
} public class DeptHandle : ConcreteHandler
{
public override void Request(string str)
{
NotifyProperty.Reminder?.Invoke("主管处理"+str);
Successor?.Request(str);
}
}

后退按钮使用责任链

我看到堆栈炸了有人问我,为什么一按后退就炸。

我看了他的源代码,他每个页面都把后退按钮点击事件+=他的方法。

我们可以使用UWP的后退按钮,但是需要小心,在哪些处理需要知道,不可以在每个需要处理都添加事件。

那么如何添加后退按钮,才可以在需要后退的时候进行后退,可以用到上面说的设计,添加一个链,需要做一个类,如果直接写,看起来比较难。

新建一个类,这个类用做责任,通过这个类,可以做 MVVM ,如果对于这个不熟,请看 win10 uwp MVVM入门

本文告诉大家如何做出双击退出应用。

首先需要创建两个类作为责任链,请看下面。

  /// <summary>
/// 责任链模式
/// </summary>
public class FjyhtrOcbhzjwi
{
public static FjyhtrOcbhzjwi Fhnazmoul { get; } = new FjyhtrOcbhzjwi(); public bool Handle { get; set; } public void AddSuccessor(AjuvqrDqsoljna ajuvqrDqsoljna)
{
AjuvqrDqsoljna.AddSuccessor(ajuvqrDqsoljna);
} public void RemoveSuccessor(AjuvqrDqsoljna ajuvqrDqsoljna)
{
AjuvqrDqsoljna.RemoveSuccessor(ajuvqrDqsoljna);
} public void Request()
{
Handle = false;
AjuvqrDqsoljna.Request(this);
} private IHandle AjuvqrDqsoljna { set; get; } = new AjuvqrDqsoljna(fjyhtrOcbhzjwi => { });
} public interface IHandle
{
IHandle Successor
{
set;
get;
} int Hnkdqckyr { get; } void Request(FjyhtrOcbhzjwi fjyhtrOcbhzjwi); void AddSuccessor(IHandle ajuvqrDqsoljna);
void RemoveSuccessor(IHandle ajuvqrDqsoljna);
} public class AjuvqrDqsoljna : IHandle
{
public AjuvqrDqsoljna(Action<FjyhtrOcbhzjwi> request)
{
Request = request;
} /// <summary>
/// 权限
/// </summary>
public int Hnkdqckyr { set; get; } public Action<FjyhtrOcbhzjwi> Request { get; } IHandle IHandle.Successor { get; set; } void IHandle.Request(FjyhtrOcbhzjwi fjyhtrOcbhzjwi)
{
Request.Invoke(fjyhtrOcbhzjwi);
((IHandle) this).Successor?.Request(fjyhtrOcbhzjwi);
} void IHandle.AddSuccessor(IHandle successor)
{
if (((IHandle)this).Successor == null)
{
((IHandle) this).Successor = successor;
}
else
{
if (successor.Hnkdqckyr > ((IHandle) this).Successor.Hnkdqckyr)
{
var temp = ((IHandle) this).Successor;
((IHandle) this).Successor = successor;
successor.Successor = temp;
}
else
{
((IHandle) this).Successor.AddSuccessor(successor);
}
}
} void IHandle.RemoveSuccessor(IHandle ajuvqrDqsoljna)
{
if (ajuvqrDqsoljna == null)
{
return;
}
if (((IHandle) this).Successor == ajuvqrDqsoljna)
{
((IHandle) this).Successor = ((IHandle) this).Successor.Successor;
}
else
{
((IHandle) this).Successor?.RemoveSuccessor(ajuvqrDqsoljna);
}
}
}

在使用的时候,通过调用FjyhtrOcbhzjwi就可以获得插入新的处理。接下来就是需要返回的按钮,参见win10 UWP 标题栏后退

        protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
//启动后退关闭
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = Windows.UI.Core.AppViewBackButtonVisibility.Visible;
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += BackRequested;
FiontwzNdqd();
}

可以看到FiontwzNdqd函数就是做双击退出的,但是双击退出需要一个字段记录是否退出。

        private bool _ajuvqrDqsoljnaMkfsjNiydfobt;

然后就是添加双击退出的函数

        private void FiontwzNdqd()
{
var ajuvqrDqsoljna = new AjuvqrDqsoljna(fjyhtrOcbhzjwi =>
{
//双击退出
if (fjyhtrOcbhzjwi.Handle)
{
_ajuvqrDqsoljnaMkfsjNiydfobt = false;
return;
}
if (_ajuvqrDqsoljnaMkfsjNiydfobt)
{
Application.Current.Exit();
}
else
{
LyfxkdxmSzjd.Text= "再次点击退出";
_ajuvqrDqsoljnaMkfsjNiydfobt = true;
}
});
FjyhtrOcbhzjwi.Fhnazmoul.AddSuccessor(ajuvqrDqsoljna);
}

但是这样写没有动画,于是添加动画,有关动画,参见:win10 UWP 动画

        private void ViewModel_LyfxkdxmSzjd(object sender, string e)
{
LyfxkdxmSzjd.Text = e;
LyfxkdxmSzjd.Visibility = Visibility;
LyfxkdxmSzjd.Opacity = 1; Storyboard sb = new Storyboard();
DoubleAnimation animation = new DoubleAnimation
{
From = 1,
To = 0,
Duration = new Duration(TimeSpan.FromSeconds(2))
};
Storyboard.SetTargetName(animation, nameof(LyfxkdxmSzjd));
Storyboard.SetTargetProperty(animation, "Opacity");
sb.Children.Add(animation);
sb.Completed += (o, ee) =>
{
LyfxkdxmSzjd.Visibility = Visibility.Collapsed;
_ajuvqrDqsoljnaMkfsjNiydfobt = false;
};
Storyboard.SetTarget(animation, LyfxkdxmSzjd);
sb.Begin();
}

这里的动画这样写是因为在 ViewModel 有一个事件,这个事件就是通知,于是就需要添加事件,在界面显示。刚好在显示结束的时候关闭双击退出。

在我之前写的游戏win10 uwp 商业游戏进入游戏时,用户按下返回按钮,需要返回欢迎界面,那么这时候就需要添加后退的处理。

因为我添加的是 MVVM 框架,于是在跳转进游戏的 ViewModel 时添加处理。关于这个框架,请看win10 uwp MVVM 轻量框架这里,但是我不会在本文用了太多这个框架的东西。在没有看这篇文章还是可以继续阅读。

        public override void OnNavigatedTo(object sender, object obj)
{
//省略其他的代码 _ajuvqrDqsoljna = _ajuvqrDqsoljna ?? new AjuvqrDqsoljna(async fjyhtrOcbhzjwi =>
{
if (fjyhtrOcbhzjwi.Handle)
{
return;
}
fjyhtrOcbhzjwi.Handle = true; //游戏保存
await AccountGoverment.JwAccountGoverment.Storage();
//返回上一层
Send(new BackTvvxwlwIlibbcpMessage(this)); //fjyhtrOcbhzjwi.Handle = true; 不要写在后面 }){
Hnkdqckyr = 10
};
FjyhtrOcbhzjwi.Fhnazmoul.AddSuccessor(_ajuvqrDqsoljna);
}

上面代码主要是添加在后退时,保存游戏和返回到上一层,代码最重要的是使用fjyhtrOcbhzjwi.Handle = true,于是在他后面的处理就可以知道自己需要或不需要处理。

当然自己添加的处理也是需要判断当前是否已经有权限比他高的进行处理,如果有,就不处理。这样写就可以在游戏进行返回。

上面代码用到框架只有一句Send(new BackTvvxwlwIlibbcpMessage(this)) 他可以让页面返回上一页,只需要发送消息,不需要知道如何去做。

需要知道的是关于 async 可能出现一个问题,请看代码,最后我去掉了fjyhtrOcbhzjwi.Handle,说不要写在后面。这里的意思是如果调用一个方法,这个方法有 await 那么这个方法如果不是 async Task 那么就会直接被跳过,不会往下面执行,所以如果把最后一句代码替换前面的,那么就会调用责任链的下一处理,但是没有告诉他已经处理了。所以在责任链,需要注意同步和异步的转换,如果实在需要,那么请参见我的博客,如何把异步转同步。

2019-9-2-C#-设计模式-责任链的更多相关文章

  1. iOS设计模式 - 责任链

    iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...

  2. java 设计模式 -- 责任链模式

    设计模式 – 责任链模式 介绍: 责任链模式是一种动态行为模式,有多个对象,每一个对象分别拥有其下家的引用.连起来形成一条链.待处理对象则传到此链上,在此链进行传递,且待处理对象并不知道此会被链上的哪 ...

  3. 浅谈Python设计模式 -- 责任链模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 之前在最开始就聊了Python设计模式有三种,其中关于创建型和结构型设计模式基本 ...

  4. 【设计模式】Java设计模式 - 责任链模式

    [设计模式]Java设计模式 - 责任链模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 目录 [设计模式]Java设计模式 - 责 ...

  5. 设计模式-责任链模式Chain of Responsibility)

    一.定义 职责链模式是一种对象的行为模式.在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...

  6. 我的Java设计模式-责任链模式

    今天来说说程序员小猿和产品就关于需求发生的故事.前不久,小猿收到了产品的需求. 产品经理:小猿,为了迎合大众屌丝用户的口味,我们要放一张图,要露点的. 小猿:......露点?你大爷的,让身为正义与纯 ...

  7. Java设计模式-责任链模式

    提出问题: 最初接触责任链模式就是在struts2中,在当时学的时候看了一眼,大概知道了原理,最近在复习,模拟struts2,说是模拟只是大体模拟了struts2的工作流程,很多东西都是写死的,只是为 ...

  8. 设计模式——责任链(chain of responsibiltiy)

    责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象. 每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象.也就 ...

  9. Java与设计模式-责任链模式

    责任链模式属于行为型设计模式之中的一个,怎么理解责任链?责任链是能够理解成数个对象首尾连接而成,每个节点就是一个对象.每个对象相应不同的处理逻辑,直至有一个对象响应处理请求结束.这一种模式成为责任链模 ...

  10. php设计模式-责任链模式

    责任链模式更像是一种简化多种场景下调用处理的一种设计模式,特别适合if-else分支判断很多的场景.比如是根据不同会员等级给予不同的优惠力度. 它的定义:对象的调用是由下家的应用连接起来的处理链.一直 ...

随机推荐

  1. elasticsearch聚合桶排序、分页实战

    很多时候业务上需要分组排序分页的场景,类似于mysql的group by xxx limit 0 10.so,当数据同步到es后,相同的需求场景也出现了.背景:商品根据商品销量排序,销量数据是以sku ...

  2. 《Effective Java》笔记

    2. 创建和销毁对象 1. 静态工厂方法替代构造器 优点: 名称清晰 每次调用不必new对象 可以返回原返回类型任意子类型对象 返回的对象可以随着调用而发生改变 返回的对象所属的类,在编写该静态工厂方 ...

  3. KingbaseES V8R3 集群运维系列 -- db vip和cluster vip管理

    ​ 案例说明: KingbaseES V8R3集群集成了DB VIP(应用连接)和Cluster VIP(集群管理),本案例描述了两种vip在集群的相关配置及集群故障时vip漂移的问题. 适用版本: ...

  4. List和ObservableCollection的转换

    1.我们后台查询全部List数据的时候,前台需要ObservableCollection展示 这个时候List需要转换成ObservableCollection public static Obser ...

  5. 链表栈(LinkedListStack)

      链式栈:就是一种操作受限的单向链表,每次入栈一个元素,向链表中添加一个节点,出栈一个元素,释放一个节点.因为栈具有"后进先出"的特点,如果每次在链表的尾部进行插入和删除,就要遍 ...

  6. 12 CSS 的float属性

    12 CSS 的float属性 流动布局 流动模型(Flow),即文档流,浏览器打开HTML网页时,从上往下,从左往右,逐一加载. 在正常情况下,HTML元素都会根据文档流来分布网页内容的. 文档流有 ...

  7. 小师妹学JavaIO之:文件读取那些事

    目录 简介 字符和字节 按字符读取的方式 按字节读取的方式 寻找出错的行数 总结 简介 小师妹最新对java IO中的reader和stream产生了一点点困惑,不知道到底该用哪一个才对,怎么读取文件 ...

  8. Go 语言输出文本函数详解

    Go语言拥有三个用于输出文本的函数: Print() Println() Printf() Print() 函数以其默认格式打印其参数. 示例 打印 i 和 j 的值: package main im ...

  9. HMS Core 3D精准室内定位技术,打造“店铺级”出行体验

    2022年4月28日,在华为折叠旗舰及全场景新品发布上,华为Mate Xs 2折叠屏手机搭载由HMS Core定位服务(Location Kit)提供的3D精准室内定位技术,为用户提供了"店 ...

  10. 力扣436(java&python)-寻找右区间(中等)

    题目: 给你一个区间数组 intervals ,其中 intervals[i] = [starti, endi] ,且每个 starti 都 不同 . 区间 i 的 右侧区间 可以记作区间 j ,并满 ...