状态机学习及对一段 java 代码的改写

摘要:
我从这个例子中了解到,Java也支持私有接口,并且可以直接生成实现接口的对象,而无需创建接口的实例。我记得,在互联网上有很多人声称C#中的委托设计违反了OO的设计原则,但我们可以从这个例子中看到,委托确实非常方便,在某些情况下可以大大简化设计。与原著中的Java程序示例相比,我们在一个类中定义了一个私有接口,然后定义了它的实现,导致了许多一句话的代理方法,我觉得非常臃肿和复杂。

《敏捷软件开发:原则、模式与实践》这本书中的第 29 章讲解了 State 模式,例子是地铁里的十字转门。书中对于状态机的实现,有一个范例是使用迁移表来实现(程序 29.12, P382),这里不列出详细代码。
我在这个例子里面了解到,原来 java 还支持 private interface,并且可以不创建接口的实例,而直接生成一个实现了接口的对象。使用的语法是类似于 C# 里匿名函数一样的内嵌定义语法。
不过,例子中的 interface 定义的作用,仅仅是为了能够方便的创建迁移表,以及在循环遍历迁移表的时候,可以用一致的语法去调用方法。这可不就是 C# 的 delegate 所起的作用吗?
因此我用 C# 语法重写了这个例子,由于使用了 delegate,代码减少了大概一半。
记得在网上也看到有不少说法称 C# 中delegate 的设计违反了 OO 的设计原则,但是从这个例子中我们可以看到,delegate 确实非常方便,在某些情况下可以大幅度简化设计,相比而言原书上的 java 程序例子,在一个 class 内部定义 private interface,然后再定义其实现,导致了很多只有一句话的代理方法,感觉非常臃肿和复杂。最主要是这里的 interface 定义是 private 的,变得毫无疑义。因此用 delegate 语法替换是一种便捷而无害的做法。
思考:并非纯粹 OO 的语言就是最好的语言,很多场景下,OO 跟过程式混合使用会带来更高的生产力。比如 python 和 delphi 就都支持这样的特性。
附 C# 的实现代码:

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
namespaceStateMachine1
{
classProgram
{
staticvoidMain(string[]args)
{
TurnstileControllercontroller
=newTurnstileController();
Turnstileturn
=newTurnstile(controller);
turn.DoEvent(Event.Coin);
turn.DoEvent(Event.Coin);
turn.DoEvent(Event.Pass);
turn.DoEvent(Event.Pass);
Console.ReadLine();
}
}
publicenumState
{
Locked,
Unlocked
}
publicenumEvent
{
Coin,
Pass
}
publicclassTurnstileController
{
publicvoidLock()
{
Console.WriteLine(
"Lock");
}
publicvoidUnlock()
{
Console.WriteLine(
"Unlock");
}
publicvoidAlarm()
{
Console.WriteLine(
"Alarm");
}
publicvoidThankYou()
{
Console.WriteLine(
"ThankYou");
}
}
publicclassTurnstile
{
Statestate
=State.Locked;
//这个属性暴露出来是为了让测试类获取或设定十字转门的初始状态publicStateState
{
get{returnstate;}
set{state=value;}
}
privateTurnstileControllercontroller;
//用delegate代替java的privateinterface实现privatedelegatevoidAction();
//表示状态迁移表的一个条目privateclassTransition
{
publicStateCurrentState;
publicEventEvent;
publicStateNewState;
publicActionAction;
publicTransition(StatecurrentState,Eventevt,StatenewState,Actionaction)
{
this.CurrentState=currentState;
this.Event=evt;
this.NewState=newState;
this.Action=action;
}
}
privateList<Transition>transitions=newList<Transition>();
publicTurnstile(TurnstileControllercontroller)
{
this.controller=controller;
//构造状态迁移表AddTransition(State.Locked,Event.Coin,State.Unlocked,newAction(controller.Unlock));
AddTransition(State.Locked,Event.Pass,State.Locked,
newAction(controller.Alarm));
AddTransition(State.Unlocked,Event.Coin,State.Unlocked,
newAction(controller.ThankYou));
AddTransition(State.Unlocked,Event.Pass,State.Locked,
newAction(controller.Lock));
}
privatevoidAddTransition(StatecurrentState,Eventevt,StatenewState,Actionaction)
{
transitions.Add(
newTransition(currentState,evt,newState,action));
}
///<summary>///处理事件
///</summary>///<paramname="evt"></param>publicvoidDoEvent(Eventevt)
{
foreach(Transitiontranintransitions)
{
if(state==tran.CurrentState&&evt==tran.Event)
{
state
=tran.NewState;
tran.Action.Invoke();
//原书遗漏这个操作break;
}
}
}
}
}

免责声明:文章转载自《状态机学习及对一段 java 代码的改写》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇竞态与线程安全CentOS8安装RabbitMQ3.8.16下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Web--js高级--11月30日随笔

一: 面向对象的三种方式: 1.单例模式 2.工厂模式 3.构造函数 js天生自带的类 Object 基类: Function Array Number Math Boolean Date Regexp String 二:事件 浏览器客户端上客户出发的行为都成为是事件 所有的事件都是天生自带的,不需要我们去绑定,只需要我们去触发。 通过 obj.事件名=...

Modle/View/Delegate框架+QSqlQuery类实现QT和MYSQL交互

2020的春节,武汉的疫情让我安心在家学QT,很喜欢https://www.devbean.net/category/qt-study-road-2/文章,深入浅出,很接地气。虽然也存在一些问题,但觉得值得初学者一读。 QT库一个很庞大的系统,由于时间和精力有限,不能系统的分门别类的总结相关知识点,概念及常规应用,这里先留下一些粗浅认识,做一个结点吧,后续...

Hibernate-入门教程

首先了解hibernate的目录结构 . +lib antlr.jar cglib-full.jar asm.jar asm-attrs.jars commons-collections.jar commons-logging.jar ehcache.jar hibernate3.jar jta....

LMAX Disruptor—多生产者多消费者中,消息复制分发的高性能实现

解决的问题 当我们有多个消息的生产者线程,一个消费者线程时,他们之间如何进行高并发、线程安全的协调? 很简单,用一个队列。 当我们有多个消息的生产者线程,多个消费者线程,并且每一条消息需要被所有的消费者都消费一次(这就不是一般队列,只消费一次的语义了),该怎么做? 这时仍然需要一个队列。但是: 1. 每个消费者需要自己维护一个指针,知道自己消费了队列中多少...

QT基础三

4.1The Central Widget QMainWindow的中央区域可以被任何类型的widget占据。 4.2Subclassing QTableWidget QTableWidget会自动创建QTableWidgetItem来存储用户的输入。 QTableWidgetItem类并不是widget,而是一个纯粹的data class。 QTabeW...

WebSocket实战

前言 互联网发展到现在,早已超越了原始的初衷,人类从来没有像现在这样依赖过他;也正是这种依赖,促进了互联网技术的飞速发展。而终端设备的创新与发展,更加速了互联网的进化; HTTP/1.1规范发布于1999年,同年12月24日,HTML4.01规范发布;尽管已到2012年,但HTML4.01仍是主流;虽然 HTML5的草案已出现了好几个年头,但转正日期,遥...