DCI中场景的另一种实现和思考


下面的解决方案,要比 http://www.jdon.com/jivejdon/thread/41011
更好一些吧。

--------------------------------------------------------

我们不必回避某些实际的技术问题,而是应进一步把非领域代码和底层代码相分离,
而分离也不必绕太多弯。

server.get...可以理解为一个用例,而Context是一个场景。
但是我们有时候,场景内部不应该结合REQ和RES对象,这时候可
以用cxt.handle进行处理,比如显示什么的。
--------------------------------------------------------
server.get('/testcxt',function(req,res){

var Context = require('./Context');
var role = "lion";
var cxt = new Context(role);
/**
init 是在执行context场景之前调用的方法,
self参数是表示context自身。
例如,甚至可以把 req 添加到 cxt 中,但这样又不表示侵入cxt本身。
可以加入任意的东西。
cxt.init = function(self){
self.req = req;
}
*/
cxt.init = function(self){
console.log('init'+self);
// 做一些初始化的事情。
}

/**
handle 是当context执行之后调用的方法,
也就是业务完成后,处理的方法,
result是领域层完成业务后的结果,
handle内部可以进行一些后备处理,比如页面显示等。
*/
cxt.handle = function(result){
res.send(result); // 显示结果
// 当然不一定只处理显示
// 这里的优势是,res对象不会被嵌入到 Context 内部
// 而res可以被handle直接访问到,这是利用了Javascript的闭包实现的。
}

cxt.run();

});
[该贴被liontseng于2011-05-09 13:38修改过]

这样做还是不错的。在落地方面,如何将场景和技术上请求响应进行结合,确实存在不匹配问题,不自然的情况,应该在方法思想上有一个创新。

恩,这方面需要思考。
我另外觉得底层处理方面可以嵌入到Role角色的方法中。
这样角色在特定场景内发挥作用并不会污染领域概念。
或者...... 还是大家多思考思考了,还有其他的方式吗?


另外,我用代码来做一个 “注册功能” 的用例场景。结合一楼的那种写法


>>> RegContext 类

var Context = require('../Context'),util = require('util');
var RegContext = module.exports = function(regrole){
Context.call(this);
this.regrole = regrole;
}
util.inherits(RegContext,Context);

RegContext.prototype.interact = function(handle){
this.regrole.reg(handle);
}



>>> 调用代码
var regrole = new RegRole(data);
var cxt = new RegContext(regrole);
cxt.handle = function(result){
response.send(result);
}
cxt.run();


>>> RegRole角色类 代码,userRepo是User的仓储对象。

var Role = require('../Role'),util = require('util'),userRepo = global.userRepo;

var RegRole = module.exports = function(user){
Role.call(this,user);
}

util.inherits(RegRole,Role);

RegRole.prototype.reg = function(callback){
userRepo.save(this.sourceData,function(err){
callback(err);
});
}



[该贴被liontseng于2011-05-09 15:08修改过]

注册场景下引入一个注册角色RegRole似乎有些牵强,各位觉得呢?
貌似角色这个东西不一定非得要在程序中映射出来,比如这个“注册”案例。
[该贴被achilleswar于2011-05-09 16:27修改过]

2011年05月09日 16:25 "@achilleswar"的内容
注册场景下引入一个注册角色RegRole似乎有些牵强,各位觉得呢?
貌似角色这个东西不一定非得要在程序中映射出来,比如这个“注册”案例。 ...

不知道,你是否是这样的观点:注册登录不属于领域。若果是,我表示同意。

所持的观点,我以前说过。现在再说一点,因为偏题了,所以也免大篇章说了。

注册,是指某实体成为领域一部分,也就是说这个时候并没有什么角色、业务等概念。属于系统级服务范畴。

更简单的说法就是,我们分析业务时,是不应该包含系统的,因为这系统正是将要做的,现在并不存在。分析一个并不存在的系统,作为业务,不觉得很奇怪么?

DCI不应受限于DDD,Context应该就是用例的实现。而是否属于“领域”这个又受限了DDD的现实的业务领域,同时我们是否应该摆脱DDD,DDD在DCI中只是一种思维过渡,并不能在实际项目中左右DCI,而DCI直接对应于用例需求。

2011年05月09日 17:25 "@SpeedVan"的内容
不知道,你是否是这样的观点:注册登录不属于领域。若果是,我表示同意 ...

我的意思是有些时候死搬硬套一些东西,比如在注册场景中引入一个“注册角色”的概念显得有些不自然,偏离了用户的心智模型?

对应用例固然是好的,但用例只体现了功能,并没有体现核心逻辑。个人认为,DCI中的I是体现Data间的活动,并不是用户作用于Data的行为。

不自然是有原因的,用户是一个很模糊的概念,对于具体业务,他无法体现职责,他自身也没有明确是一个登录前还是登录后的身份。注册角色是谁担当呢?是游客,当系统不存在这一实体概念时,注册角色也就无从谈起。

在DCI中的场景中,要有对象参与,但并非每次都要有领域实体参与。
DCI中的I是角色之间的交互,而不一定是领域实体之间的交互。
参看Banq大哥贴 http://www.jdon.com/jivejdon/thread/41011#23133739
[该贴被liontseng于2011-05-11 12:46修改过]

注册用例的另一种描述。


var Context = require('../Context'),util = require('util'),Role = require('../Role');

// 注册场景
function RegContext(appliant,leadership){
Context.call(this);
this.appliant = appliant;
this.leadership = leadership;
}

util.inherits(RegContext,Context);

RegContext.prototype.interact = function(handle){
this.leadership.stamp(applicant,handle);
}

// 申请人角色
function Applicant(user){
Role.call(this,user);
}

// 工商局领导角色 *注意* 领导在这里不需要领域实体对象,而仅仅是一个角色。所以没有写成 Role.call(this,user);
function Leadership(){
Role.call(this);
}

Leadership.prototype.stamp = function(applicant,callback){
// 工商盖章,注册一个商户
}

Leadership.prototype.validat = function(applicant,callback){
// 验证商户是否符合注册标准
}

exports.RegContext = RegContext;
exports.Applicant = Applicant;
exports.Leadership = Leadership;


[该贴被liontseng于2011-05-11 14:50修改过]

我并不觉得那贴与我思维冲突。首先,角色都由谁担当?我认为是实体,角色只是一具行尸走肉,是实体带给他灵魂。场景里的角色都是带灵魂的,所以才有活动。一件事发生了,我们一定能够说出谁和谁(以什么身份)干什么,而不是身份与身份干什么。而我们能称"谁",也就具有唯一标识的实体。回到注册上,谁来当注册角色呢?

你这种情况,我曾经想过的,谁申请了,谁允许了,当中的实体还是角色,是需要深入辨识的。因用手机回复有点麻烦,回家了再说。

是这样的,我喜欢用代码说明,如下:


var user = userFactory.create(name,...);
var applicant = new Applicant(user); // 申请者角色
var leadership = new Leadership();
// 领导角色
var regcxt = new RegContext(applicant,leadership);
// 生成注册场景
regcxt.run(handleResultFunction);


这里的领导角色并不需要领域实体,我觉得没有这个必要,否者的话会受到DDD的一些OLD概念限制,好像必须采用service方式似的,但其实,我觉得角色并不一定要有一个领域Entity来充当。这种方式也可以代替老的DDD的Service概念。

[该贴被liontseng于2011-05-11 15:19修改过]

2011年05月11日 10:54 "@SpeedVan"的内容
当系统不存在这一实体概念时,注册角色也就无从谈起 ...

有道理.