惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
S
Securelist
P
Proofpoint News Feed
D
DataBreaches.Net
Cisco Talos Blog
Cisco Talos Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Project Zero
Project Zero
A
About on SuperTechFans
罗磊的独立博客
WordPress大学
WordPress大学
月光博客
月光博客
Latest news
Latest news
C
Cyber Attacks, Cyber Crime and Cyber Security
GbyAI
GbyAI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 三生石上(FineUI控件)
F
Fortinet All Blogs
W
WeLiveSecurity
Attack and Defense Labs
Attack and Defense Labs
V
Visual Studio Blog
Blog — PlanetScale
Blog — PlanetScale
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Privacy International News Feed
AI
AI
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Stack Overflow Blog
Stack Overflow Blog
M
MIT News - Artificial intelligence
Help Net Security
Help Net Security
T
Tor Project blog
V
Vulnerabilities – Threatpost
C
Cisco Blogs
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
MyScale Blog
MyScale Blog
雷峰网
雷峰网
MongoDB | Blog
MongoDB | Blog
Forbes - Security
Forbes - Security
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
T
Threat Research - Cisco Blogs
B
Blog RSS Feed
博客园 - 叶小钗
N
News and Events Feed by Topic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Simon Willison's Weblog
Simon Willison's Weblog
C
CERT Recently Published Vulnerability Notes
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
N
News and Events Feed by Topic

博客园 - 白板

招聘.NET SE/SSE/SA -(内部推荐,上市互联网公司) 招 Senior .NET Software Engineer / Architect (ShangHai HP GDCC Regular) Road on EA & IT Governance Seriously I Enjoy Coding 企业应用层面的架构人员---持续关注SpringSide(续) 持续关注SpringSide “官方”辨析---Business Model, Business Object Model, Domain Model, Object Model, Data Model Form Data Validation Framework? 重读《重构》之杂感 ROI of Agile Approach 读 《J2EE Without EJB》 几点WebService集成体会 界面集成 Involve me and I'll understand Look at the logic host by OO or SP from Maintaince View Tools Support for high level architecture HP's Scalable world-wide .net-connected service framework 大公司 or 小公司? Thoughtworks - Orchestration Patterns
在UI层使用Domain逻辑的一些探讨
白板 · 2005-12-12 · via 博客园 - 白板
 


今年做了两个基于Rich Domain Model的系统, 如何在UI层使用业务逻辑,公司之前的系统在这上面的处理上让人非常不爽,自己重新设计了一套还是觉得有点别扭,拿出来给感兴趣的人探讨下。

先给出系统逻辑架构简图

 逻辑结构:
UI层使用WinForm,和后台间传递DTO(DTO后面还会详细介绍);
Business层逻辑上包含Façade层和Domain层,Façade不是简单的对应于Façade模式,还兼容了Biz Flow Control, DTO Assemble(将Domain对象转换成DTO对象或者相反)等Application Service 方面的内容和逻辑,Business层只有Façade对UI层可见;
Persistence层负责和数据库打交道,因为不是重点就不多作介绍了。

我们规定UI层只能使用无行为的DTO对象,通过分析,我们发现大部分的界面都可以使用和Domain对象内容一致的DTO对象,比如Domain里面有Order->OrderItem这么个Domain对象的聚合体,在UI的某个界面往往也正好只需要同样的数据聚合体。所以我们划分出EntityDTO和FlatDTO的概念,EntityDTO和Domain对象一一对应,只包含Domain对象的数据,DTO Assembler有工具可以自动完成这两者的映射,FlatDTO就是任意数据内容的组合(和PEAA里面的DTO的介绍一致)。

物理结构:
系统UI和Business层物理分离的,通过Remoting通信,公司之前的这种Remoting结构的系统一直存在两个问题,1)因为WinForm提供了丰富的界面操作,有的人为了使用后台和业务相关的逻辑频繁的调用Remoting对象,完全不考虑效率,大部分操作背后都进行了若干次的Remoting调用,2)有的人考虑到了效率,把很多不访问到后台资源的检查和逻辑都写到UI层,这样导致逻辑分散难于管理难于重用。(我承认UI必不可少得包含一些逻辑,比如非空输入检查,这种检查往往UI和Domain都需要做的,但有些业务特别是计算还是只由Domain去处理好些)

为了缓解上述两个问题,我考虑了另外一种稍微有点怪异的结构。因为UI层对RemoteFaçade依赖于实现,而非倚赖于接口,所以我们的后台组件必须全部部署到客户端(ok,我知道这样不好,或许我会写篇文章来介绍这其中的权衡),也就是说,如果不使用到后台资源,我们完全可以在客户端直接使用Domain,所以我们设计了LocalFacade和RemoteFacade两个组件.RemotingFacade都是Remoting对象,UI层如果访问RemoteFacade对象的话,肯定是要访问后台数据库,后台文件之类的资源;而LocalFacade是普通对象,如果UI访问它,则LocalFacade首先将DTO转化成DomainObject,然后使用Domain逻辑,而这一切都在客户端处理,速度肯定比Remoting快得多(稍后才看到EJB的Local和Remote接口,不知道它的两种接口是否可以同时使用)。

这样处理最明显的好处就是,从逻辑结构上来讲,所有和业务对象本身相关的检查、计算等所谓的业务逻辑都可以全部驻留在Domain里面,而不会分散到UI层。另外一个好处是,如果客户端已经拿到了检查或计算所必要的相关数据,就不用费力的往服务端再跑一趟了。

看到这里,细心的人可能有个疑问,为什么要使用EntityDTO,而不可以把Domain对象直接暴露给UI,这样就可以省掉EntityDTO的维护,EntityDTO和Domain映射的维护以及映射导致的效率损失(里面有很多反射操作)。Ok,这确实是我也看着不爽或许以后会改过的地方,之前的一些想法包括,1)UI层不应该直接使用Domain的细粒度接口(实际上因为WinForm提供的丰富的界面操作,以及大量的业务检查,细粒度接口的访问的概率倒是挺大的),2)Domain对象反转倚赖于Persistence层的接口,因为我们认为Domain在进行某些检查或者计算时,它所需要的数据可能还在数据库里面,所以需要domain自身直接去访问Persistence层,这种访问是只读的,也就是说,写数据还是必须由Façade层调用Persistence接口去实现。这样做实际上并非必要的,也可以通过Façade层获取到所有Domain逻辑所需要的数据,这样Domain就可以与persistence完全隔离,不过这样的domain逻辑给人感觉不连贯,相关的讨论很多这里就不多说了。因为Domain里面的行为可能回访问到数据库,所以,为了避免在UI误用了这些接口,我们提供了LocalFacade,LocalFacade由后台对Domain完全清楚的开发人员开发,可以减少这种误用的可能性,当然这个理由很牵强,毕竟通过测试就可以避免这个问题了。

在使用的过程中,还碰到另外一个头疼的问题,比如判断某个定单是否已经发送,可以通过Order.Status = ORDER_STATUS_SENDOUT来判断,但是UI人员建议提供Order.IsSend()的行为,这个要求如果在后台的话,无可厚非,毕竟IsSend()的判断逻辑很可能到后面不仅仅是对一个状态的判断,但是如果使用行为的话,就需要调用LocalFacade接口,也就是说OrderLocalFacade需要有IsOrderSent( OrderEntityDTO order)的接口,然后在接口里面还需要把EntityDTO转化成DomainObject(要么用N多的反射自动映射,效率降低;要么手动映射,维护成本巨大),然后才能通过Domain的行为来进行IsSend()的检查,LocalFacade暴露如此细粒度的接口,其维护的成本和发射的效率损失都是让人很难接受的,要知道,客户端这样的需求实际上是非常多的。

总之,权衡是件很头疼的事,尤其是使用分布式的架构,也难怪MartinFlower,Rob Johnson等人都在极力呼吁不要使用分布式的架构。上述的讨论主要是针对C/S、Remoting的这种架构,在B/S架构里面根本无须LocalFacade和RemotingFacade的区分,但是也会面临Web层如何使用Domain逻辑的问题,再加上AJAX的引入,如何解决JavaScript里面直接包含业务逻辑的问题,应该比我这里列出的问题更严峻。

最后,我考虑到另外两种方案,以后或可尝试,1)后台使用Rich Domain,前台使用Manager。Manager都是静态的方法,专门在客户端处理业务逻辑。优点是效率提高了,不用维护LocalFacade,不用把Domain部署到客户端,缺点是后台的业务逻辑会在前台大量的重复,无法使用到OO的继承多态所带来的灵活性。2)前台不包含逻辑,所有需要访问到业务逻辑的地方都走一趟服务器,这要求更好的设计利用DTO,尽量减少在一个操作背后往返服务器的次数,优点是开发人员爽了,缺点是客户不爽了。好象又回到我最早提出的两个问题上,唯一不同的是,之前的系统在这方面都没有做特别的分析和约束,不同的开发人员在不同的地方都可能采用不同的方式,整个UI层使用Domain逻辑显得很混乱,需要把这种无意识的状态变成有意识的状态。

-----------

-----------
看了age0的回复,感觉误解有点大,抱歉介绍得不清楚,补充一份概要的部署图,注意客户端和服务端的Domain是同一组件,在客户端运行的代码,通过人为控制不会去访问到服务端的资源(虽然domain里面有对存储层的反转依赖)