程序员 2014-11-4 每日奇妙之旅
推荐:《精通Node.js开发》 《Angular.js视频详解》 腾讯QQ
1405491181
微信号forjs_org
先做个计划
domain框架开发
-
Event 已完成
-
Actor 完善 1个番茄钟
-
Actor 单元测试 1个番茄钟
-
Repository 完善 3 个番茄钟
-
Repository 单元测试 1个番茄钟
-
EventBus 完善 2个番茄钟
-
EventBus 单元测试 1个番茄钟
-
Domain 完善 2个番茄钟
-
Domain 单元测试 1个番茄钟
今天的重要且紧急的任务,就是完成domain框架开发,并进行必要的测试。
沏一杯咖啡,开始奇妙之旅吧!这是一个激动人心的创造过程。
完善 Actor
需要先修改一下Actor#listen方法,我准备把所有方法都通过provider方式提供。
[listen](eventName, handleName) {
this.emit('listen', {eventName: eventName, handleName: handleName});
}
然后修改 call
方法
call(commandName, data, caller) {
this[commandName](data,{
apply:(eventName, data)=> {
this[apply](eventName, data, caller);
},
listen:this[apply].bind(this)
});
}
e.g.
it("#listen", function (done) {
var User = Actor.extend({
typeName:"User",
methods:{
changeName: function (name,service) {
service.listen("change","finishChange");
},
finishChange: function (data, service) {
done();
}
}
})
var user = new User();
user.on("listen", function (event,methodname) {
this.call("finishChange",methodname);
});
user.call("changeName");
})
这个单元测试代码,我对 apply测试修改并测试通过 ,但 #listen 这个测试没通过,还需要找一下原因。
另外我对listen方法的实现方式不满意,还需要进一步优化。
原因找到了,是call方法的bug,正确代码是:
call(commandName, data, caller) {
this[commandName](data,{
apply:(eventName, data)=> {
this[apply](eventName, data, caller);
},
listen:this[listen].bind(this) // here
});
}
Actor开发基本这样,当然这只是preview,我觉得不够完善的,还是构造器部分
和错误处理和异常处理
,之后逐步完善吧。
还有就是 listen
方法,我觉得应该优化一下,不过眼下够用了。
我把 when 修改成私有,通过注入方式加入到各个方法里,另外把call进行了修改:
[when](event, set) {
if (event.name === "remove") {
set("alive", false);
}
if(this[otherWhen])
this[otherWhen](event, set);
}
extend方法进行了修改,把when注入到各个方法里
static extend(options) {
var typeName = options.typeName;
if (typeNames.indexOf(typeName) !== -1)
throw new Error("type name is exist.")
var methods = options.methods;
class Type extends Actor {
}
Object.defineProperty(Type.prototype, "typeName", {
get() {
return typeName;
}
})
// 这是新加的
Object.defineProperty(Type.prototype, otherWhen, {
value: options.when
})
for (var k in methods) {
Object.defineProperty(Type.prototype, k, {
value: methods[k]
})
}
return Type;
}
用一个单元测试when
it("#when", function () {
var User = Actor.extend({
typeName:"People",
methods:{
changeName: function (name,service) {
service.apply("changeName",name);
}
},
when: function (event, set) {
if(event.name === "changeName"){
set("name",event.data.data);
}
}
})
var user = new User();
user.call("changeName","leo");
user.get("name").should.eql("leo");
})
Repository 的完善
一个仓储需要那些方法呢?
- 思考如何构造一个仓储对象
- create 创建一个Actor
- get 得到一个Actor对象
- remove 删除一个Actor
一个仓储需要 Actor类和 eventstore 事件储存对象。
class Repository {
constructor(Actor, eventstore) {
this.Actor = Actor;
this.eventstore = eventstore;
this[cache] = {}
}
}
然后是create方法
*create(data) {
let actor = new this.Actor(data);
let result = yield this.getFromSnapShot(actor.id);
let err = result[0];
let snapshot = result[1];
let stream = result[2];
err = (yield this.createSnapshot({
aggregateid: actor.id,
aggregate: this.Actor.name,
data: actor.json,
revision: stream.revision
}))[0];
if (err) {
throw err;
} else {
this[cache][actor.id] = actor;
return actor;
}
}
进行单元测试创建一个Repository对象
var Repository = require("../dist/lib/Repository");
var Actor = require("../dist/lib/Actor");
var ES = require("eventstore");
describe("Repository", function () {
var User = Actor.extend({
typeName:"User"
}),es = new ES,repos;
it("#new", function () {
repos = new Repository(User,es);
})
})
测试通过,很lucky,上午就这样,下午继续奇妙之旅吧!
继续 …
*create(data) {
let actor = new this.Actor(data);
let result = yield this.getFromSnapShot(actor.id);
let snapshot = result[0];
let stream = result[1];
yield this.createSnapshot({
aggregateId: actor.id,
aggregate: this.Actor.name,
data: actor.json,
revision: stream.revision
})
this[cache][actor.id] = actor;
return actor;
}
测试代码:
it("#create", function (done) {
co(function *() {
var user = yield repos.create({name:"leo"});
user.get("name").should.eql("leo");
var getFromSnapShot = thunkify(es.getFromSnapshot).bind(es);
var rs = yield getFromSnapShot(user.id);
var snap = rs[0];
should.exist(snap);
done();
})()
})
下面实现 get 方法
*get(id) {
let actor;
if (actor = this.getFromCache(id)) {
return actor;
}
let result = yield this.getFromSnapShot(id);
if (actor = this.getFromCache(id)) {
return actor;
}
let snapshot = result[0];
let stream = result[1];
if(!snapshot){
return null;
}
let snap = snapshot.data;
let history = stream.events;
actor = new this.Actor();
// mix aggregate object.
actor.loadSnap(snap);
var historyv = [];
history.forEach(function (e) {
historyv.push(e.payload);
})
actor.loadEvents(historyv);
this[cache][actor.id] = actor;
return actor;
}
单元测试
it("#get", function (done) {
co(function* () {
repos.clear(uid);
var user = yield repos.get(uid);
user.get("name").should.eql("leo");
done();
})()
})
ok,测试通过!