责任链模式的具体应用

 

1.业务场景

生产车间中使用的条码扫描,往往一把扫描枪需要扫描不同的条码来处理不同的业务逻辑,比如,扫描投入料工位条码、扫描投入料条码、扫描产出工装条码等,每种类型的条码位数是不一样,因此通过条码长度来进行业务区分。

2.初步设计

面对此场景,能够想到的最简单的设计就是使用if...else if...或者swith进行判断,因此,我们编写的代码如下

 1 switch(barCode.length)
 2 {
 3     case 3:
 4         DoSomething1();
 5         break;
 6     case 4:
 7         DoSomething2();
 8         break;
 9     case 5:
10         DoSomething3();
11         break;
12     default:
13         DoSomething4();
14         break;
15 }

使用是if...else if...或者switch已经基本上满足了需求,以后需要添加扫描场景,只需要增加判断,完成对应的方法即可。

作为一个程序员,仅仅满足需求的话,往往降低了对自己的要求,同时,随着扫描业务的增加,switch中的代码逐渐增加,多到我们自己都觉得这段代码读起来就像是吃着前天剩下的硬馒头一样,难以下咽。

3.设计提升

上述场景完全可以使用设计模式中的责任链模式来进行优化,实施步骤如下:

3.1 定义处理结果

一个处理在责任链上流动时,有两种结果,一是不能处理,转给其后继者,二是可以处理,同时又引出两种结果,处理成功和处理失败。因此,对处理结果统一定义为枚举类型

 1 public enum HandleResult
 2 {
 3   /// <summary>
 4    /// 成功
 5    /// </summary>
 6    Success=0,
 7    /// <summary>
 8    /// 失败
 9    /// </summary>
10    Failed = 1,
11    /// <summary>
12    /// 未处理
13    /// </summary>
14    Unhandle = 2
15 }

3.2定义业务抽象类AbstractBarCodeHandler

定义业务抽象类,包含一个属性“Successor”,用于标记其后继者,一个公共方法“HandleRequest”,当调用真正的业务处理方法时返回未处理,则调用其后继者进行处理,一个抽象方法“HandleRequestCore”,每个扫描业务具体类,需要实现此方法,并对条码进行处理。

 1     public abstract class AbstractBarCodeHandler
 2     {
 3         /// <summary>
 4         /// 责任处理的后继者
 5         /// </summary>
 6         private AbstractBarCodeHandler mSuccessor;
 7
 8         /// <summary>
 9         /// 责任处理的后继者
10         /// </summary>
11         public AbstractBarCodeHandler Successor
12         {
13             get
14             {
15                 return mSuccessor;
16             }
17
18             set
19             {
20                 mSuccessor = value;
21             }
22         }
23
24         /// <summary>
25         /// 请求处理方法
26         /// </summary>
27         public HandleResult HandleRequest(string barCode)
28         {
29             var result = HandleRequestCore(barCode);
30             if (result == HandleResult.Unhandle)
31             {
32                 if (Successor != null)
33                 {
34                     Successor.HandleRequest(barCode);
35                 }
36                 else
37                 {
38                     Console.WriteLine($"The BarCode:{barCode} do not handle.");
39                 }
40             }
41             return result;
42         }
43
44         protected abstract HandleResult HandleRequestCore(string barCode);
45     }

3.3定义业务实现具体类

每个具体的条码扫描业务,都定义一个类,继承自AbstractBarCodeHandler,并实现其抽象方法,比如,

  LocationBarCodeHandler:工位条码处理类
  LocationInBarCodeHandler:入库条码处理类
  LocationOutBarCodeHandler:出库条码处理类
  MaterialBarCodeHandler:物料条码处理类
  ToolingBarCodeHandler:工装条码处理类

3.4 生成责任链

依次对每个类进行初始化,并设置其后继者,比如:

  工位条码处理类实例.Successor=入库条码处理类实例;
  入库条码处理类实例.Successor=出库条码处理类实例;
  出库条码处理类实例.Successor=物料条码处理类实例;
  物料条码处理类实例.Successor=工装条码处理类实例;

3.5处理过程

当条码枪扫描一个条码,便发起了一个处理请求,该请求在责任链上依次流动(工位->入库->出库->物料->工装),若某个节点不能够处理,则需要交接去后继者,若能够处理,则返回处理结果,当所有的节点都无法处理,需要给出对应的提示。

----

ServiceStack.Redis订阅发布服务的调用

 

1.Redis订阅发布介绍
Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息。类似于设计模式中的观察者模式。
发布者和订阅者之间使用频道进行通信,当需要发送消息时,发布者通过publish命令将消息发送到频道上,该消息就会发送给订阅这个频道的订阅者。

图片来自于http://www.runoob.com/redis/redis-pub-sub.html

2.ServiceStack.Redis
  ServiceStack.Redis是Redis的C#版本的客户端,是ServiceStack的一部分。
    ServiceStack的地址为https://servicestack.net

3.订阅者
首先创建RedisClient,然后调用CreateSubscription()方法创建订阅客户端,然后设置订阅客户端的几个事件:
OnMessage:接受到消息时。
OnSubscribe:订阅频道时。
OnUnSubscribe:取消订阅频道时。
最后,调用subscribeToChannels(channelName),订阅频道。
详细代码如下:

 1 /// <summary>
 2     /// Redis订阅
 3     /// </summary>
 4     public static void Subscribe()
 5     {
 6         using (RedisClient consumer = new RedisClient("127.0.0.1", 6379))
 7         {
 8             //创建订阅
 9             IRedisSubscription subscription = consumer.CreateSubscription();
10             //接受到消息时
11             subscription.OnMessage = (channel, msg) =>
12             {
13                 Console.WriteLine($"从频道:{channel}上接受到消息:{msg},时间:{DateTime.Now.ToString("yyyyMMdd HH:mm:ss")}");
14                 Console.WriteLine($"频道订阅数目:{subscription.SubscriptionCount}");
15                 Console.WriteLine("___________________________________________________________________");
16             };
17             //订阅频道时
18             subscription.OnSubscribe = (channel) =>
19             {
20                 Console.WriteLine("订阅客户端:开始订阅" + channel);
21             };
22             //取消订阅频道时
23             subscription.OnUnSubscribe = (a) => { Console.WriteLine("订阅客户端:取消订阅"); };
24
25             //订阅频道
26             subscription.SubscribeToChannels("channel1");
27         }
28     }

4.发布者
首先创建RedisClient,然后调用PublishMessage(channelName,message)发布消息。
详细代码如下:
RedisClient client = new RedisClient("127.0.0.1", 6379);
string message = "发布消息测试";
client.PublishMessage("channel1", message);

到目前为止,一个简单的Redis发布订阅就完成了。

5.Redis发布服务
使用发布者仅仅能够发布消息,但是不能够检测一些事件的变化,Redis中还有一个RedisPublishServer的类,里面包括一些事件能够使我们很好地检测服务的运行。
OnMessage:接受到消息;
OnStart:发布服务开始运行时;
OnStop:发布服务停止运行时;
OnUnSubscribe:订阅者取消订阅时;
OnError:发布出现错误时;
OnFailover:Redis服务器冗余切换时;
发布服务端初始化完成后,调用Start()方法,开始执行发布服务。

发布服务执行后,执行消息的发布client.PublishMessage时,发布服务端也能够接受到发布的消息。
详细代码如下:

 1 public void Publish()
 2     {
 3         //PooledRedisClientManager
 4         IRedisClientsManager redisClientManager = new PooledRedisClientManager("127.0.0.1:6379");
 5         //发布、订阅服务 IRedisPubSubServer
 6         RedisPubSubServer pubSubServer = new RedisPubSubServer(redisClientManager, "channel1")
 7         {
 8             OnMessage = (channel, msg) =>
 9             {
10                 Console.WriteLine($"从频道:{channel}上接受到消息:{msg},时间:{DateTime.Now.ToString("yyyyMMdd HH:mm:ss")}");
11                 Console.WriteLine("___________________________________________________________________");
12             },
13             OnStart = () =>
14             {
15                 Console.WriteLine("发布服务已启动");
16                 Console.WriteLine("___________________________________________________________________");
17             },
18             OnStop = () => { Console.WriteLine("发布服务停止"); },
19             OnUnSubscribe = channel => { Console.WriteLine(channel); },
20             OnError = e => { Console.WriteLine(e.Message); },
21             OnFailover = s => { Console.WriteLine(s); },
22         };
23         //接收消息
24         pubSubServer.Start();
25     }
每天进步一点点...
 
分类: S-Redis

责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用的更多相关文章

  1. ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现

    ASP.NET MVC 学习笔记-2.Razor语法   1.         表达式 表达式必须跟在“@”符号之后, 2.         代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...

  2. ServiceStack.Redis订阅发布服务的调用(Z)

      1.Redis订阅发布介绍Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息.类似于设计模式中的观察者模式.发布者和订阅者之间使用频 ...

  3. ServiceStack.Redis订阅发布服务的调用

    1.Redis订阅发布介绍 Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息.类似于设计模式中的观察者模式. 发布者和订阅者之间使用频 ...

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

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

  5. C#设计模式:责任链模式

    设计模式是面向对象编程的基础,是用于指导程序设计.在实际项目开发过程中,并不是一味将设计模式进行套用,也不是功能设计时大量引入设计模式.应该根据具体需求和要求应用适合的设计模式.设计模式是一个老话题了 ...

  6. 23种设计模式--责任链模式-Chain of Responsibility Pattern

    一.责任链模式的介绍 责任链模式用简单点的话来说,将责任一步一步传下去,这就是责任,想到这个我们可以相当击鼓传花,这个是为了方便记忆,另外就是我们在项目中经常用到的审批流程等这一类的场景时我们就可以考 ...

  7. ResponsibleChain(责任链模式)

    /** * 责任链模式 * @author TMAC-J * 老板讲任务交给CTO,CTO自然不会亲自去做,又把人物分配给项目经理,项目经理再把任务分配给组长,组长再分配给个人 * 如果中途哪个环节出 ...

  8. C#设计模式-责任链模式

    在现实生活中,有很多请求并不是一个人说了就算的,例如面试时的工资,低于1万的薪水可能技术经理就可以决定了,但是1万~1万5的薪水可能技术经理就没这个权利批准,可能就需要请求技术总监的批准,所以在面试的 ...

  9. 责任链模式/chain of responsibility/行为型模式

    职责链模式 chain of responsibility 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处 ...

随机推荐

  1. Echarts 异步数据加载遇到的问题

    看了Echarts官网异步加载数据的Demo var myChart = echarts.init(document.getElementById('main')); // 显示标题,图例和空的坐标轴 ...

  2. Hadoop集群安装指南(CHD5.9.1)(分布式+图文详解)

    centos7.1,CDH5.9.1,3台机器,终极指导安装 下载链接如下: 安装文件下载链接如下: 链接:https://pan.baidu.com/s/1RQYNiWn9a-T8GXcCsoDBs ...

  3. 洛谷 P1085 不高兴的津津

    这道题就是经典的条件分支的题https://www.luogu.org/problemnew/show/P1085 code: #include <stdio.h> int main() ...

  4. FWT板子

    板子: #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> u ...

  5. InnoDB INFORMATION_SCHEMA Temporary Table Info Table

    InnoDB INFORMATION_SCHEMA Temporary Table Info Table INNODB_TEMP_TABLE_INFO提供有关InnoDB实例中当前活动的用户创建的In ...

  6. ArchLinux 安装笔记

    前言 在开始之前,请在心中默念三遍: Arch Linux 是世界上最好的发行版, 我一定能掌握她. 环境 VM ware + UEFI + 500G 虚拟磁盘 + 2G 内存 + 桥接网络 下载镜像 ...

  7. gcc编译详解

    GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器.它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分.GCC原本作为GNU操作 ...

  8. Insert or Merge

    7-13 Insert or Merge(25 分) According to Wikipedia: Insertion sort iterates, consuming one input elem ...

  9. linux中的vi命令

    linux的重要的几个命令如下: ①,光标的操作 1,gg,G,nG,:n gg移到文档的开头一行,G移动到最后一行,nG移动到第n行,到指定的行. 2,H,M,L 光标分别移动到这个界面的最上边,中 ...

  10. luogu1856 [USACO5.5]矩形周长Picture

    看到一坨矩形就要想到扫描线.(poj atantis) 我们把横边竖边分开计算,因为横边竖边其实没有区别,以下论述全为考虑竖边的. 怎样统计一个竖边对答案的贡献呢?答:把这个竖边加入线段树,当前的总覆 ...