责任链模式的具体应用

 

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. java+selenium+maven+IntelliJ IDEA 搭建简单的UI自动化测试环境

    1. 用IntelliJ IDEA新建一个maven工程 2. 在pom.xml中添加依赖: <dependency> <groupId>org.seleniumhq.sele ...

  2. rc-local.service服务启动失败,导致rc.local中的开机启动服务不能启动

    chmod  +x   /etc/rc.d/rc.local 打开/etc/rc.local文件,将启动非后台执行的指令的最后添加 &,以使相关指令后台运行,然后启动服务 systemctl  ...

  3. LINUX:关于Redis集群搭建 、和搭建项目中遇到的问题

    文章来源:http://www.cnblogs.com/hello-tl/p/7804225.html 0.Redis的简单安装 1.安装redis依赖 # yum install gcc tcl g ...

  4. ARM Linux 3.x的设备树(Device Tree)(转)

    http://blog.csdn.net/21cnbao/article/details/8457546

  5. python 连接docker

    发现15年写过的一小段,先mark一下,后续玩儿起来 import docker c = docker.Client(base_url='unix://var/run/docker.sock',ver ...

  6. HDU 1242 Rescue 营救天使

    Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is describe ...

  7. Oracle dataguard failover 实战

    Oracle dataguard  failover 实战 操作步骤 备库: SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINIS ...

  8. BZOJ3126: [Usaco2013 Open]Photo

    n<=200000个点,m<=100000个区间,每个区间有且仅有一个点,求最多几个点,无解-1. http://www.cnblogs.com/Chorolop/p/7570191.ht ...

  9. 【PD】PowerDesigner生成数据字典

    1.首先说明我使用的环境 --------------------------------第一种:不按模板导出导出数据字典----------------------------- 2.打开PDM模型 ...

  10. vs2010 相对路径

    相对路径是针对后缀为vcxproj文件而言的. 在VS的工程中常常要设置头文件的包含路径,当然你可以使用绝对路径,但是如果你这样设置了你只能在你自己的机器上运行该工程:如果其他人拷贝你的工程到其他机器 ...