node.js的 Domain framework JSDM

13-02-20 brighthas
大家好,我是利奥brighthas,下面介绍一下 node.js 的 CQRS框架[ JSDM ]

参看项目

https://github.com/brighthas/jsdm

以前我开发过cqrsnode是纯粹CQRS的框架,后来工作室本身需要开发相对复杂的系统,而且要浏览器也要有很好的抗“复杂性”,所以我改版成 JSDM。

JSDM不是完全传统的CQRS DDD框架,以下说明一下。

// 这是伪代码,不是完整的,只是说明一下基本用法

var  domain =  require("jsdm")();

domain
   .bindAgg(...)
   .bindCommandHandle(...)
   .bindService(...)
   .listen(...)
   .bindAgg(...)
   .bindDB(db)
....
   .seal();  // 封印

// 封印后,只剩下如下三个方法有效。
//  on /  once 是 监听器,从domain外部监听内部,但数据都是只读的,改变 domain内部状态只能通过exec方式执行 command来操作 domain内部。

domain.on(...);       
domain.once(...);
domain.exec(...);    // 执行 command  ,对应着 command handle.

<p>

这里需要说明的是 domain.bindDB(db) 这里的db只有一个 get(id,callback) 方法,开发者可以自己实现一个get方法即可, jsdm不是传统的 CQRS ,去除了传统的 event store 的回溯的功能。目的是提供中小型项目也能快速开发的目的,并享受CQRS的精华机制。

那么, db.get 只有这个方法, update 、 remove 、 save呢?

在domain的内部,当 new XXXAggre() 一个根的实例时,会触发一个 create event, 相应的还有 update / remove 的事件产生,而domain new一个Aggre时,会先存放在 cache 中。只有从Repository 得到 Aggre实例时,会先从cache找,如果没有会调用 db.get 方法并放入 cache然后回调出来。

remove 、 update 、 save 实现很简单。

domain
.listen("create",function(event){
    // 当然实现非常简单,可以使用内存、file 、mysql,一切都可以。
    testdb.save(event.aggreType,event.data);
})
.listen("update",function(event){
     testdb.save(event.aggreType,event.data);
})
.listen("remove",function(event){
    testdb.remove(event.aggreType,event.data);
})

<p>

另外如果想实现事件的store,直接 domain.listen(" * " ... ) 监听 * 号,表示监听全部事件。

domain.listen("*",function(event){
    //  save event object.
})
<p>

如果项目很复杂,可以使用多个 domain

var domain1,domain2 ..... , domain n 
<p>

[该贴被brighthas于2013-02-20 10:52修改过]

              

5
brighthas
2013-02-27 18:42
JSDM是一个node.js的CQRS Domain开发框架。下面介绍一下他的基本命令。

通过 npm install jsdm 安装,如果浏览器需要,可以采用component install brighthas/jsdm 方式安装。

jsdm -a Aggre01,Aggre02 这个命令可以创建两个Aggre

jsdm -c handle01, handle02 可以创建两个 command handle

jsdm -e Aggre01.*.changeName 该命令可以创建监听Aggre01的changeName的事件监听器

jsdm -s service01,service03 该命令可以创建 服务。

jsdm ls 命令可以查看domain内部有什么组件

[该贴被brighthas于2013-02-27 18:43修改过]

wee
2013-03-02 18:00
你好

我有两个问题,

第一 event handler一般一会处理保存或者持久化

第二 业务的验证是的哪一块,比如说名字的唯一性,只有get方法好像不行

brighthas
2013-03-04 20:22
第一个问题:我想深度的剖析一下 Domain , 我不是讨论 DDD 和 CQRS,我是讨论“域”的概念,那么“域” Domain 就是一个黑匣子,也可以说是一个稍大的模块Module,那么Domain的内部状态的改变只能通过 command 方式,拿JSDM框架举例。

domain.exec 方法用来执行domain内部命令command的,内部触发对应的 command handle.来处理。

而我们的思维往往局限在数据库方面,其实当下domain是一个独立体,他真实需要的数据都在他自身的 cache缓存中,也叫“内存式真实体” , 这些真实体才是domain运行的根本。

而repository在domain内部只有一个get方法,用来得到一个根的“内存式真实体”。

那么如上所述,我们也就是可以把这些模模块块分一下类:

以下是Domain所在的位置

UI layout + APP layout + Domain layout + write DB

所以, event handle 把监听domain内部的变化持久到 DB 中,因为这中持久化不是 domain 内部的职责。

不知道我说明白没有。

第二个问题可以采用2种方法,一个是service用于验证服务,一个是用command handle 进行验证,我写一下代码,大概如下:

// 先定义一个Aggre根的类
{
   init:function(data){
   },
   proto:{
       updateName:function(args,my){
              var self = this;
              // 检查是否有重复的名字
              my.service("checkRepeatName",{name:args.name,function(repeat){
                    // 如果重复那么不会更改名字
                    if(repeat){}else{
                          my.data("name",args.name);
                         // 激活
                          self.active();
                    }
  
            }})
       },
       // 激活方法
       active:function(){略}
   },
   name:"User"   
}

// 这种方法就是先创建一个aggre object,创建的这个可以定义为非激活的对象,然后updateName,如果通过,就激活对象。
<p>

// 第二个方法,采用command handle 进行处理
// 定义一个command handle
{
   name:“create a User”,
   handle:function(args,my){
          //先验证,也用service
           // 检查是否有重复的名字
              my.service("checkRepeatName",{name:args.name,function(repeat){
                    // 如果没有重复的,就创建一个User
                   if(!repeat){
                           var User= my.getAgg(“User”);
                           var user = new User({name:'利奥'});
                    }
              })
   }
}
<p>

还有其他方式,先介绍这两个

[该贴被brighthas于2013-03-04 20:40修改过]

brighthas
2013-03-05 09:36
还有一个方法,代码如下:

第一步,定义一个判断是否User重名的service服务

function checkUserNameRepeat_Service(args,my){
     // 具体代码略 ...
     args.callback(err) // 如果重复err就不为空。
}
<p>

第二步,定义一个User Aggre的init 初始化方法

// 在此输入java代码
......
function init(data,cb,my){

    // 执行判断是否重名的服务
    my.serivce( "checkUserNameRepeat_Service" ,{name:"利奥",callback:function(err){
       // 如果重名
       if(err){
             cb(err);
       }else{  // 如果不重名
             cb(undefined,data)
       } 

   }});

}
......
<p>

再在 command handle 里面用repository创建时,内部会自动通过 init 进行验证处理.

  // 得到 User 仓储
  var UserRepo = my.getRepo("User");
  UserRepo.create(data,function(err,aggreObj){
        if(err){ // 创建失败,可能是名字重复  }
      // 如果成功,那么继续。。。
     .....

      
  })

<p>

猜你喜欢
3Go 1 2 3 下一页