关于将Jdon框架提升为DCI框架的设想

在]Jdon框架 6.4案例中(这里),我使用Domain Events实现了一种DCI,Domain Events和DCI是两种不同角度看同一个问题,而DCI是从软件分析如彩色UML四色原型直接映射过来的,因此让开发者直接和DCI打交道,能够减少不必要的转换翻译失真。

那么我的设想是将Domain Events作为DCI底层机制,层层封装,Dirsruptor--->Domain Events ---> DCI,DCI是最高级别的层次。

另外也看到Ruby领域正在构想DCI模式或框架,他们遇到一些关于场景的问题,文章:DCI patterns - how to write DCI contexts in Ruby

应用对象是否应该知道场景?
Should the application object (a model) know about the contexts?
有三个选择:
1. 应用对象可以访问所有可能场景,MVC的控制器只要这样调用: application.register_new_user(..) ,是应用进行场景初始化。

2.应用有能力知道全局性场景: NewUserContext.new(..).

3.控制器消失(正如Rails, banq注:JdonFramework也是), 控制器和场景的匹配是在一个配置文件中。

该文最后说:到目前为止,所有的Ruby 的DCI的例子似乎有点冗长。这是因为DCI并不能直接翻译到如Ruby这样的​​动态语言。

现在,我们在jdonFramework中使用“事件”翻译DCI到Java中,这个路子虽然有点绕,但是只要把其封装起来,让开发者直接面对DCI,也许是一条办法。

下面的问题是如该文提出的三个选择,我个人比较倾向于消灭MVC,见:MVC已死。用DCI场景替代MVC的控制器,用REST URL替代控制器与页面交互,这样消灭了控制器,就是消灭了MVC。

因为@oojdon 已经开发了一个开源框架JdonMVC, 我注意到其中有@Context标注,所以,也许我们在JdonMVC的REST上加工一下, 消灭MVC的DCI框架就可能探囊可取了。

有兴趣者可讨论一下可能性。

[该贴被banq于2011-09-13 12:17修改过]
[该贴被banq于2011-09-13 12:19修改过]
[该贴被banq于2011-09-13 12:20修改过]
[该贴被banq于2011-09-13 12:27修改过]

各位,我不懂什么数据库设计,事务与性能是对立吗?未必。。。如果将事务划分为事件的话吗?

文中提及。。控制器、场景、还有全局性。。。

我只想说。。可能背后是统一的。

但还没有解决数据管理问题。。数据的多维性和数据完整性。。。

嘿嘿。。。乱说一通。。。望各位大牛砖之!
[该贴被xiqi92于2011-09-13 13:28修改过]

2011年09月13日 13:11 "@banq"的内容
那么我的设想是将Domain Events作为DCI底层机制,层层封装,Dirsruptor--->Domain Events ---> DCI,DCI是最高级别的层次。 ...

这个意思是事件引导场景的走向,还是说以“事件引发场景,场景发出事件”这样的方式形成链呢(击鼓传花)?
[该贴被SpeedVan于2011-09-14 15:12修改过]

2011年09月14日 14:47 "@SpeedVan"的内容
这个意思是事件引导场景的走向,还是说以“事件引发场景,场景发出事件”这样的方式形成链呢 ...

都不是,角色发出事件,场景引发事件,主要是DCI封装事件,不知是否属于纸里包不住火?

事件从界面发出后(REST动词引发的事件),直接调用REST 的URL资源,在对应/xxx/xxx的资源的处理器中,实际是场景发生地。比如Post动词引发了/save这个对象,现在一般做法/save是MVC的控制器,实际上因为REST的介入,已经不存在MVC这样结构模式,因为REST本身是一种资源被动词事件激活的结构,与MVC角度不一样,没有必要两者扯在一起。

我认为/save应该是DCI中场景Context,REST的逻辑意思是:以资源Product的POST为例子,这是将资源Product提交,也就是创建资源product,那么REST服务端为响应这个事件,必然要启动一个相应的场景来处理,就像你到政府部门发出投诉事件,必然有一场接受你投诉的场景发生,在这个场景中,也许是某个人头戴乌纱帽扮演监察官接受处理你的投诉。

所以,我认为REST+DCI是行得通,而且含义非常通俗。

有一篇文章:DCI和WEB认为在Ruby中REST + RAILS + DCI行不通,我觉得是作者无法真正理解REST含义所致:没有人真正理解REST or HTTP



[该贴被banq于2011-09-14 15:25修改过]

2011年09月14日 15:24 "@banq"的内容
就像你到政府部门发出投诉事件,必然有一场接受你投诉的场景发生,在这个场景中,也许是某个人头戴乌纱帽扮演监察官接受处理你的投诉。 ...

前面讲了REST如何和DCI的场景衔接。继续上面例子演绎:

这监察官接受了你的投诉事件后,一般他也不处理,也没有权力处理,而是再转到其他相关部分处理。这正好是我们用Domain Events实现场景Context的部分,在场景中,我们通过Domain Events异步将任务又推给了事件的消费者@Consumer了。

REST ---> Context --> Domain Events ---> consumer真正处理者

所以,整个环节细化后是:
1. Web客户端 发出post/put/get/delet四个REST动词事件后 进入第2步
2. 服务端URL如/product,而/product一般标在class方法上,如
@Path("/product")
@POST
public Represent create(User user)
这个create方法其实是我们context中一种interactions交互方法。
3.在create(User user)中实现类似前面ComputeContext方法里面的代码,比如 usermodel.remember(); 而usermodel.remember()内部是
domainEvents.saveDomainObject(this);

其实JdonMVC中的那个com.jdonmvc.restful.UserCommandContext 它就是一个DCI的Context.


事件大致可分为4大类:
0)界面与业务逻辑层之间的交互事件。
1)业务逻辑层,场景之内的事件(用于激活模型,发挥作用,扮演角色)。
2)业务逻辑层,场景之间的事件(用于切换场景)。
3)业务逻辑层与持久化层之间的交互事件。

一般来说,凡是涉及到层与层之间的交互,事件可采用异步模式,提升伸缩性。
而在层内,则需要细分。轻活(事件处理花费的时间较少),采用同步模式;重活(事件处理花费的时间较多),采用异步模式。

除了上面所说,最近我还在想:
0)将UI、Domain、DB看成一个动态的整体,如何使用四象图去描绘,这可能要舍弃或改造UI、Domain、DB这些概念。
1)事件是刻画行为特征很普遍的一种方法,除了从UI领域借鉴的事件监听器的实现方式,有没有更优雅的方式,比如模式匹配。
2)事件还有一个用法,就是用来实现场景规约(不是场景本身),目前我所想到的比较粗糙的方法,比如“策略模式+中介者模式/责任链模式”等。

2011年09月14日 15:55 "@banq"的内容
REST ---> Context --> Domain Events ---> consumer真正处理者 ...

REST的四个动词post/put/get/delet 应该在服务端分别有四个场景应对,这四个场景中,用的是同一资源data model,四个不同角色,可以分别是:
creator(创建者;接受处理post的角色)
updator(修改者;接受处理put的角色)
remember(记忆者:接受处理get的角色)
forgettor(失忆者:接受处理delete的角色)

我们只要在场景中将这四个角色注入到领域模型中,即可完成REST。

这是REST+DCI天然的处理方式,多么自然?


我觉得大家对于“场景”一词的定义有些模糊,如果以领域为界,至少可以分为领域内部场景和领域间场景。

理了一下思路:
  前面大家在这里讨论了半天,更多的是强调事件。说起“事件”,大家的认知基本是一致的,但对于“场景”似乎是各说各的,根本就不一致。
  首先我建议应按照“读写分离”的原则,把业务场景分为“读场景”和“写场景”,可以认为所有的场景都是这两种场景的组合。从DDD的角度看,复杂的“读场景”是对各领域模型的读聚合,虽然“读场景”在开发中的代码量较大,但实际上逻辑比较简单。而“写场景”虽然代码量不大,但却是逻辑最复杂的地方。没有事件概念的“写场景”只能应付简单逻辑。但在“写场景”的实战中,我发现仅有“事件”概念是不够的,似乎还应有总线的概念。
  纯属个人之见,希望大家指正。


整合jdonmvc的demo出炉了。


public class ResourceUpdate {

@[author]In[/author](value = "entityFactory", type = BeanType.COMPONENT)
private EntityFactory entityFactory;

@[author]In[/author](value =
"roleAssigner", type = BeanType.COMPONENT)
private RoleAssigner roleAssigner;

@Path(
"/user")
@PUT
public Represent update(UserModel user) {
roleAssigner.assignRoles(user);
user.updateMemory();
return new State(
"/");
}

2011年09月17日 18:04 "@oojdon"的内容
把业务场景分为“读场景”和“写场景”,可以认为所有的场景都是这两种场景的组合。 ...

这个Idea很不错,我前面讨论的REST场景,其实也包括了这两种场景。这可能是一种适合简单CRUD情况下的一种场景。

现在问题来了,REST有其作为资源的"CRUD"场景;而数据库也有其数据的"CRUD"场景,存在两种场景了,是两种并存映射,还是合并呢?

主要考虑精简,不能太琐碎,如创建是一个角色,CRUD就有四种角色,两种并存就八中角色,复杂了些,搞两个:REST的CRUD场景;数据库的RepositoryContext仓储场景。

因为REST的CRUD场景和RepositoryContext要衔接,实际是在REST的CRUD场景处衔接RepositoryContext;REST场景应是无形的,不需要有形,也就是专门搞个REST场景类class。

@oojdon 根据我前面帖子在其crud案例中,设置了creatRole等REST的CRUD场景和角色,我现在思路改变,觉得可能没有必要,直接在REST处理类中传递给RepositoryContext。

当然,如果用REST的CRUD场景封装RepositoryContext场景也是一种选择,一些NoSQL数据库就是这么做的,REST是他们的接口。但是一般我们要在中间加一个领域层,一般是这样:

REST的CRUD场景 + Domain Model + RepositoryContext;

REST的资源不直接是数据库的数据,而是Domain Model,这样我们在Domain Model上可以引入更多DCI。


REST的CRUD场景 + Domain Model + RepositoryContext;
+ ComputeContext
+ Business1Context
+ Business2Context
+ Business3Context

整合了oojdon的jdonMVC和DCI(无需Domain Events)案例见:
SimpleJdonFrameworkTest.rar

使用一个REST场景com.jdon.framework.test.web.ResourceManagerContext整合CRUD操作,如下代码是一个新增资源的操作:


@Path("/users")
@POST
public Represent post(UserModel user) {
if (validate(user))
return new Html(
"/newUser.jsp", "user", user);
user.setUserId(Integer.toString(user.hashCode()));
//将角色分配给user数据模型
RepositoryManagerIF rm = (RepositoryManagerIF) roleAssigner.assign(user, new RepositoryManagerEventImp());
//发出保存的异步Domain Events
rm.remember(user);
return new State(
"/");
}


[该贴被banq于2011-09-19 22:07修改过]

banq老师,我没看懂你的新的SimpleJdonFrameworkTest.rar中的代码,好像没有用到Struts1,不知用到了哪些知识和框架?

2011年09月27日 09:32 "@zjsong"的内容
好像没有用到Struts1,不知用到了哪些知识和框架? ...

前面说了,@OOJDON 的JdonMVC,它是一个REST风格的MVC框架,类似于Spring3.0的SpringMVC: http://code.google.com/p/jdonmvc/