飞鸽03:模块分解

意大利面条代码是一种很直接的实现方法。但是,毕竟日后维护会引发不便。

不包含加密和文件传输飞鸽程序可以分解成两部分:

1. GUI。呈现图形界面,相应用户输入。实际上就是把读取键盘的线程变成GUI而已,但是已经不包含了任何与网络相关的部分,如socket维护等。这里维护系统状态,如邻居表:就是通讯录,记录每个邻居的IP地址、用户名、主机名、昵称、群组、在线情况(以及可用的加密算法等)。

2. Communicator,通信器。负责维护socket,接收和解析数据报、并根据GUI发来的请求,组装相应的报文,发出相应的报文。本身唯一的状态就是socket本身。

这里GUI作为主对象,创建和控制Communicator。它们之间有如下通信接口:


----------------------------
<< interface >>
ICore // GUI实现这个接口
----------------------------
PROPERTIES:
+ get_context() : {username,host,nick,...}
// 取得当前主机的信息,包括用户名等。
----------------------------
EVENTS:
+ node_notify(ipaddr,username,host,nick,group,away)
// node_notify通知GUI新的节点加入。
+ incomming_message(ipaddr,message_text,sealed)
// 当有新消息到达时,这个方法会调用。
----------------------------



----------------------------
<< interface >>
ICommunicator // Communicator实现这个接口
----------------------------
EVENTS:
+ refresh()
// 命令通信器广播当前主机加入的命令IPMSG_BR_ENTRY。
+ send_message(ipaddr,message_text,sealed)
// 向某个用户发送消息。
+ read_notify(ipaddr,packet_num)
// 告知某邻居,它发出的消息已读。
----------------------------


实现仍然用Python语言实现。

当然,在Python语言里是没有所谓的Interface这样的东西的。(一定想要在Python里用Interface的请找Zope Interface)全靠对象自己自觉。执行的时候对象只管调用方法,不会考虑它是否存在。但是Python里面没有异步的Event这种机制。上述UML里的events也是用同步的方法调用来实现。

程序中一共有两个活跃的线程:一个是GUI线程;另一个是socket接收线程。Python的线程间通信明显不如Erlang语言强大(废话)。如果引入MessageQueue,必然要引入Mutex和Condition的话,对于这样的小程序太overkill了。事实上现在的这个程序就是线程不安全的。

GUI用PyGTK实现,设计如下:

[img]http://cloverprince.iteye.com/upload/attachment/125836/ab464429-20a2-38ba-9fab-770c96522c83.png[/img]

本来是觉得,把所有东西都放在屏幕上,有一种一目了然,很爽的感觉。现在看看似乎也不行,太挤了。

这样的设计,还是有问题的

- GUI,感觉扩充已经是问题了。塞的满满的。

另一个问题是

- 目前线程的结构,是按照输入来区分的线程:一个用户输入,另一个网络输入。输入之后,执行者分属不同的对象,但方法调用却位于各个模块中。换句话说,两个不同线程在同时忙于多个互相交叠的一组对象。这使得两个线程的责任不清(在对象级别降低耦合了,但在线程级别没有),还使锁不可缺少。另外在GTK中使用线程本身就会遇到一些问题。

可行的解决方法:

* 是否可能将socket IO集成到GTK的MainLoop中,使得数据包的到达成为一个事件。这样就可以用单线程事件轮询的方式,以处理GUI事件相同的方法处理IO。

优点是避免多线程的麻烦。缺点也是抛弃了多线程的方便。IO的处理必须以“有限状态自动机”的形式构造(即设计模式里的State模式)。明显,用Python语言实现状态机会遇到困难,也有可能给调试添加麻烦。

下一个问题:

- GUI中,状态(通讯录/邻居列表)如何保存。目前的实现方法是使用GTK的ListStore。虽然不是什么问题,但是这使得程序和UI耦合更加紧密——毕竟ListStore是为GTK的TreeView专门设计的结构。

理想的模块化,是将程序分为至少3部分:通信器/核心/GUI。核心保存状态,执行协议操作,而GUI只是表现这样的状态。耦合度松到一定程度,使得只要在一个XML说用哪个GUI,用哪个核心,用哪个通信其,它们如何如何连接,就可以执行。(依赖注入?)

用MVC的语言说,通讯录就是M,GUI就是V,核心就是C。

* 我相信,软件必须有一定的耦合度。高耦合的代码不易应对变化;而低耦合的代码必须用足够多的“胶水”连接它们,反而麻烦。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值