追求简单的设计.
也许你的设计功能很强大,但能够在满足你需求的前提下尽量简单明了设计.
当你的设计过于复杂的时候想想是不是有其它路可以走,你站在别人的角度想下,如果别人看了你的设计会不会心领神会,还是焦头烂额.
当然我们可以站在牛人的肩膀上,有很多的设计模式可以借鉴,拿来主义未尝不可.
好回归正题,先上图:
每层的角色职责分别为:
1:Guitar.Comet 封装通用接口,包括消费者接口,消息接口,消息总线接口,客户端接口(抽象为两种模式:1为推模式,2为拉模式),消息分发器接口,另外抽象出消息体模型.为了能够支持各种消息格式,我定义的字段比较泛化,包括消息名,发送时间,ID(GUID),消息体(以key/value形式存储),发送的客户端名.
2:Guitar.Comet.Client 封装基于SignalR的客户端实现.
(1)消息分发到服务端(目前单线程异步分发);
(2)代理客户端,订阅消息,监听消费者,响应消费者支持同步和异步两种方式,如果消息是无序的,无相关性则可异步处理.如果非得让消息有序处理,那也行!当然这可能造成阻塞.
(3)长连接/断开后重连服务端机制;客户端连接上服务端后,连接通达一直打开(其实有定时 间隔的重连的),如果服务端offline,那客户端肯定保证消息不会丢,其次当服务端online后客户端重连服务端并继续发消息.
3:Guitar.Comet.Host 封装基于SignalR的服务端实现.
(1) 分发消息给订阅的消费者;
(2) 当消费者端口后负责重试发送,一旦消费者online,消息重新推给订阅者消费,当然这只是在消息没有过期的前提下,不然消费者一下收到N封消息,那怎么受得了,所以这里面有个消费消息的策略,给消息指定过期时间或统一消息在指定时间内有效;
那为什么这样分层:我主要考虑三点:一是角色职责划分,二是独立性(可测试性)要求,三是用户使用要求;有时候我们会比较纠结分一个什么层,我们的类文件到底放在那一层(无法安放的类).我觉的从上面3点考虑会清晰点.
Guitar.Comet层的类图:
Guitar.Comet.Client层的类图:
类图关系就不多说了,看源码部分即可.
设计是偏技术的,但还是要立足于业务需求的,而领域设计既迎合了技术又重视业务,那什么是领域我理解的领域是代表者客观事实规律,而领域设计我觉的是面向对象式的去表示客观事实,技术和领域相辅相成,没有技术则领域无法落地,没有领域技术显的没有价值,那如何面向领域去思考设计,我看一些牛人的文章使用四元模式,即明确实体,角色,描述及时刻.我比较认同.
简单的设计,不简单的业务.持续优化重构.