`
robbin
  • 浏览: 4822028 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
377a9ecd-1ea1-34ac-9530-9daa53bb2a7b
robbin谈管理
浏览量:137102
社区版块
存档分类
最新评论

domain model的延伸讨论

    博客分类:
  • Java
阅读更多
domain model,又称为领域模型,是Java企业应用讨论的一个热门话题,JavaEye也曾经多次围绕这个话题讨论,我们来看个简单的例子:

引用

一个简单的公司工时管理系统,记录员工的个人信息,每个员工的工作任务分配,以及工作所属类别(例如开发,还是测试,还是培训等等),其中每个员工有n个任务,员工和任务是一对多关系,每个员工也分别隶属于多个不同的工作类别,员工和类型是多对多关联关系,而每个任务也分别隶属于唯一的工作类别,任务和类别是多对一关系。另外系统不要求对部门信息进行维护,不需要department表。因此,在这个系统中使用四张数据库表:

users表保存员工信息,有name, password, gender, department, salary
tasks表保存工作任务信息,有name,start_time, end_time
kinds表保存工作所属类别,有name
kinds_users表是一张关联表,保存users表和kinds表的多对多关联外键的

系统的功能需求如下:
1、某部门录用一名新员工
2、某部门员工总薪水总和
3、某员工已经开始但尚未结束的任务
4、给某员工分配一项任务
5、所有用户当前已经开始但尚未结束的任务
6、对某一类别,给所有和此一类别相关的员工,批量新增一批任务
7、针对任务的统计功能,给定某类别,统计当月总的任务数,已完成任务数,未完成任务数


我们先看看用ruby如何实现系统的领域模型:

class User < ActiveRecord::Base
  has_and_belongs_to_many :kinds
  
  has_many :tasks, :dependent => :destroy do
    def processing_tasks
      find :all, :conditions => ["start_time <= ? AND end_time is null", Time.now]
    end
  end
  
  def apply_task(task_name)
    self.tasks << Task.new(:name => task_name, :start_time => Date.today)   
  end   
    
  def self.all_processing_tasks
    Task.find :all, :conditions => ["start_time <= ? AND end_time is null AND user_id is not null",Time.now]
  end
end

class Task < ActiveRecord::Base
  belongs_to : owner, :class_name => 'User', :foreign_key => 'user_id'
  belongs_to :kind
  
  def self.current_month_tasks(kind)
    kind.tasks.current_month_tasks 
  end
end

class Kind < ActiveRecord::Base
  has_and_belongs_to_many :users
  
  has_many :tasks do
    def current_month_tasks
      month_begin = Date.today - Date.today.mday + 1
      month_end = Date.today - Date.today.mday + 30
      processing_tasks = find :all, :conditions => ["start_time <= ? AND end_time is null ", month_begin]
      processed_tasks = find :all, :conditions => ["end_time >= ? AND end_time <= ? ", month_begin, month_end]
      all_tasks = processing_tasks.clone
      all_tasks << processed_tasks unless processed_tasks.size == 0
      return all_tasks, processed_tasks, processing_tasks
    end
  end
  
  def add_batch_task_to_users(task_name)
    self.users.each do |user|
      task = Task.new(:name => task_name, :start_time => Date.today) 
      user.tasks << task
      self.tasks << task
    end  
  end
end

class Department
  def self.employee(username, department)   
    User.create(:name => username, :department => department)   
  end  
  
  def self.total_salary(department)
    User.sum :salary, :conditions => ["department = ?", department]
  end
end


1、某部门录用一名新员工
Department.employee("robbin","开发部")

2、某部门员工总薪水总和
Department.total_salary("开发部")

3、某员工已经开始但尚未结束的任务
user.tasks.processing_tasks

4、给某员工分配一项任务
user.apply_task("学习Java")

5、所有用户当前已经开始但尚未结束的任务
User.all_processing_tasks

6、对某一类别,给所有和此一类别相关的员工,批量新增一批任务
kind.add_batch_task_to_users("学习单元测试")

7、针对任务的统计功能,给定某类别,统计当月总的任务数,已完成任务数,未完成任务数
Task.current_month_tasks(kind)


这里值得注意的是,RoR可以很方便的采用充血的领域模型,所有的业务逻辑都可以放在相关的domain model里面。这里的user,task和kind都是对应于数据库表的领域模型,而department是不对应数据库的纯业务逻辑的domain model。总共4个ruby文件,4个domain model,55行代码,所有要写的代码都在这里了,代码量确实非常少,每个domain model的颗粒度都比较大。

然后我们再看看如何用Java:
public class User {
    private Long id;
    private String name;
    private String password;
    private String gender;
    private String department;
    private int salary = 0;
    private List<Task> tasks = new ArrayList<Task>();
    # omit getter/setter methods ......
}

# omit User's ORM Mapping file

public class Task {
    private Long id;
    private String name;
    private int duration = 0;
    private User owner;
    # omit getter/setter methods ......
}

# omit Task's ORM Mapping file

public class Kind { 
    ......
}

# omit Kind's ORM Mapping file

public interface UserDao {
    public void addUser(User user);
    public loadUserById(Long id);
    # omit CRUD and other persistent methods ......
    public List<User> findByDeparment(String department);
}

public interface TaskDao {
    # omit CRUD and other persistent methods ......
}

public class UserDaoImpl {
    # omit implementations ......
}

public class TaskDaoImpl {
    # omit implementations ......
}


public class UserService {
    private UserDao userDao;
    public setUserDao(UserDao userDao) { this.userDao = userDao; }
    public int workload(User user) {
        int totalDuration = 0;
        for (Task task : user.getTasks()) {
            totalDuration += task.duration;
        }
        return totalDuration;
    }
    public employee(String username, String department) {
        User user = new User();
        user.setName(username);
        user.setDepartment(department);
        userDao.addUser(user);
    }
}

public class TaskService {
    private TaskDao taskDao;
    public void setTaskDao(TaskDao taskDao) { this.taskDao = taskDao }
    public applyTask(String taskName, User user) {
        Task task = new Task();
        task.setName(taskName);
        task.setUser(user);
        taskDao.addTask(task);
    }
}

public class DepartmentService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) { this.userDao = userDao; }
    private UserService userService;
    public void setUserService(UserService userService) { this.userService = userService; }
    public int totalSalary(String department) {
        ......
    }
    ......  
} 

# omit IoC Container weaving configuration's file



Java版本的实现代码大家都比较熟悉,因此绝大部分代码都省略了。Java版本需要3个持久对象,3个映射XML文件,3个DAO接口和实现类,4个Service和实现类,和一个IoC的bean组装文件,总共21个文件,全部逻辑写完整,代码行数至少上千行。

通过对比,我们可以看到Java比较流行的实现是贫血的模型,按照面向对象的基本原则,对象的状态应该和它的行为封装在一起,因此Java多出来的这些XXXService是一些从纯理论角度而言应该放入其相应的持久对象中去。但是Java实现充血模型从技术上有一定的难度,如何Service方法挪入到持久对象中呢?如何解决Dao的注入问题?如何解决domain logic方法的事务封装问题?前者可以通过AspectJ的静态织入来解决,后者也许可以通过织入或者annotation声明来解决。但不管怎么说,Java从技术上很难实现充血模型,而且即使实现充血模型,也会导致一个Java类好几百行代码的状况,其代码的可阅读性,模块解藕能力都会变得很差,因此我们认为Java不适合充血模型,在表达复杂的业务逻辑的能力上,Java要比ruby差很多:

结论:
对于Java来说,更加适合采用贫血的模型,Java比较适合于把一个复杂的业务逻辑分离到n个小对象中去,每个小对象描述单一的职责,n个对象互相协作来表达一个复杂的业务逻辑,这n个对象之间的依赖和协作需要通过外部的容器例如IoC来显式的管理。但对于每个具体的对象来说,他们毫无疑问是贫血的。

这种贫血的模型好处是:
1、每个贫血对象职责单一,所以模块解藕程度很高,有利于错误的隔离。
2、非常重要的是,这种模型非常适合于软件外包和大规模软件团队的协作。每个编程个体只需要负责单一职责的小对象模块编写,不会互相影响。

贫血模型的坏处是:
1、由于对象状态和行为分离,所以一个完整的业务逻辑的描述不能够在一个类当中完成,而是一组互相协作的类共同完成的。因此可复用的颗粒度比较小,代码量膨胀的很厉害,最重要的是业务逻辑的描述能力比较差,一个稍微复杂的业务逻辑,就需要太多类和太多代码去表达(针对我们假定的这个简单的工时管理系统的业务逻辑实现,ruby使用了50行代码,但Java至少要上千行代码)。
2、对象协作依赖于外部容器的组装,因此裸写代码是不可能的了,必须借助于外部的IoC容器。

对于Ruby来说,更加适合充血模型。因为ruby语言的表达能力非常强大,现在用ruby做企业应用的DSL是一个很热门的领域,DSL说白了就是用来描述某个行业业务逻辑的专用语言。

充血模型的好处是:
1、对象自洽程度很高,表达能力很强,因此非常适合于复杂的企业业务逻辑的实现,以及可复用程度比较高。
2、不必依赖外部容器的组装,所以RoR没有IoC的概念。

充血模型的坏处是:
1、对象高度自洽的结果是不利于大规模团队分工协作。一个编程个体至少要完成一个完整业务逻辑的功能。对于单个完整业务逻辑,无法再细分下去了。
2、随着业务逻辑的变动,领域模型可能会处于比较频繁的变动状态中,领域模型不够稳定也会带来web层代码频繁变动。

附件是完整的RoR版本的项目示例代码。要运行它,需要安装MySQL数据库(InnoDB表类型),Ruby和Ruby on rails环境。在MySQL数据库中分别创建demo数据库和demo_test数据库,修改demo\config\database.yml中的MySQL数据库配置,改成你的数据库密码。然后在项目跟目录下面执行:
rake db:migrate
rake db:test:clone_structure
rake test
即创建开发环境数据库,创建测试环境数据库,和执行所有的单元测试。领域模型代码位于demo\app\models目录下面;单元测试代码位于demo\test\units目录下面
  • demo.zip (80.6 KB)
  • 描述: 完整的RoR版本的项目示例代码
  • 下载次数: 576
分享到:
评论
45 楼 chunshui 2007-03-04  
谢谢Robbin好文
44 楼 firstline78 2007-03-04  
JavaInActoin 写道
robbin 写道

你这个领域模型是根本跑不起来的。数据库根本就没有department这个表,你的department的users属性根本就是null,一跑就会出错。你的user.addTask方法也执行不了,没有Dao的支持,你再调用addTask,数据库里面也不增加记录。UserManager也不应该存在,这是属于user的domain logic。
请不要拿一个根本不能运行的错误代码出来,请先在你本地搭建一个实际的web项目,自己测试通过了,再贴出来。

单独的领域模型当然跑不起来,和其它层装配起来就跑的很以欢畅了。
我写的Domain Model是根据Eric Evans的观点来的,很多持久化(包括事务)的操作超越了业务逻辑,需要被安排在应用服务层。
你写的那段不是MF的充血模型,而是事务脚本。
robbin 写道

请不要拿一个根本不能运行的错误代码出来,请先在你本地搭建一个实际的web项目,自己测试通过了,再贴出来。

这个不是讨论问题的最佳方法,太累了,你写的代码同样不能运行
robbin 写道

    public employee(String username, String department) {   


寻找这样的错误是没有意义的,只要思路正确,在座的各位都可以把代码调试好。


OO思想或者实现不能应用到系统所有地方,JavaInActoin这么说也是很有道理的。
43 楼 newman 2007-03-04  
接chinaet的话题,从java开源大全网站获取SpringXT的摘要信息如下:

“SpringXT是Spring框架的一个扩展用于开发richer domain models与richer user interfaces的应用程序。采用Domain Driven Design设计原则。为此SpringXT提供两个框架SpringXT Modeling Framework:提供一些组件来开发rich domain model(它集中了所有业务逻辑,规则和约束,完全独立于应用程序的其它部分)并能够让它们与其它应用软件分层"优雅"结合。SpringXT Ajax Framework:一个完全与Spring MVC集成在一起,基于事件的Ajax框架。”

java开源大全网址:
http://www.open-open.com/open184107.htm

springxt官方网址:
http://springxt.sourceforge.net/index.php/Main_Page
42 楼 chinaet 2007-03-04  
大牛们,研究一下SpringXT,看看SpringXT能不能解决RICH DOMAIN MODEL的问题
41 楼 newman 2007-03-04  
robbin写道:
“Java难于实现充血模型的根本原因还是在于:Java是静态类型的语言,难以运行期任意的动态改变其行为,所以必须依赖外部容器例如IoC进行对象依赖组装,也必须依赖特定的ORM框架进行增强其行为,这些容器和框架本质上都是通过动态代理方式来增强类,其结果就是对象的设计必须符合容器对它的要求,从而限制你追求理论上更完美模型的可能性。至于继承不继承类,这个根本无关紧要。”

re:你能否回答一下RR的哪些动态特性支持了其优越的域对象模型?而这些动态特性是java中无可企及的?

“不知道大家有没有想过,为什么Java这么强调面向接口编程?面向接口编程为什么对Java这么重要?但是对于动态面向对象语言ruby来说,却根本不需要接口这种概念。这是因为在Java中是类型决定行为,所以类型的地位很重要,你一继承,对象的行为就被限制死了,所以Java很忌讳继承的使用;但是ruby的类型不决定行为,所以随便你怎么继承,也不会限制对象的行为。”

re:这种灵活完全是优点吗?我看未必。对于简单应用,你想怎么应用就怎么应用,但是应用复杂了之后呢?随意的继承,会是怎样的一种后果?是否会产生系统消化不良,导致运行效率问题,还有后期无法维护呢?
40 楼 歆渊 2007-03-04  
另外说起做Web应用来, 对于单服务器环境, 看看WoW就知道TOB应用的成熟程度了, 管理界面也是JSP的, Applet的xml通信模式和AJAX没有本质差别.

基于HBI的分布式模式也会很快成熟起来.
39 楼 歆渊 2007-03-04  
呵呵, 所以是 "主流Java" 的问题, 而不是 "Java的问题" 嘛.

TOB的应用持久类改变以后, 不需要重启应用服务器呀, 热重新部署以后就可以让数据库表结构跟着更新, 这个不是更OO Centric么? 我觉得更好啊.
38 楼 robbin 2007-03-04  
to complystill:

我没有仔细看TOB的实现,TOB相当于构建一个内存当中的对象数据库,这种编程模式和主流的基于关系数据库直接驱动的web项目差别比较大。

rails是由DB schema来动态决定对象的状态。在development环境下,任何对数据库的修改都立即会改变对象的状态行为。这和Hibernate由映射文件来动态生成数据库DDL正好反过来。但不能说谁好谁不好,在TOB中你能一改数据库schema,不需要重起应用服务器就让对象的property立刻随着改变吗?也做不到不是。





37 楼 歆渊 2007-03-04  
robbin 写道

.....
Java版本的实现代码大家都比较熟悉,因此绝大部分代码都省略了。Java版本需要3个持久对象,3个映射XML文件,3个DAO接口和实现类,4个Service和实现类,和一个IoC的bean组装文件,总共21个文件,全部逻辑写完整,代码行数至少上千行。

不要把Java一棒子打死吧, TOB上的充血模型也是Java的, 哪里不好请指点出来, 否则还是说 "主流Java实现" 比较合适.
robbin 写道

通过对比,我们可以看到Java比较流行的实现是贫血的模型,按照面向对象的基本原则,对象的状态应该和它的行为封装在一起,因此Java多出来的这些XXXService是一些从纯理论角度而言应该放入其相应的持久对象中去。但是Java实现充血模型从技术上有一定的难度,如何Service方法挪入到持久对象中呢?如何解决Dao的注入问题?如何解决domain logic方法的事务封装问题?前者可以通过AspectJ的静态织入来解决,后者也许可以通过织入或者annotation声明来解决。但不管怎么说,Java从技术上很难实现充血模型,而且即使实现充血模型,也会导致一个Java类好几百行代码的状况,其代码的可阅读性,模块解藕能力都会变得很差,因此我们认为Java不适合充血模型,在表达复杂的业务逻辑的能力上,Java要比ruby差很多:

用TOB的话, 开发者只需要关心自己的代码, 就是我给出的那么多, 没有混局的代码呀. 其余有些是在编译应用代码的时候把所有需要的额外逻辑都自动生成出来的, 不需要关心, 而且不改动应用类bytecode, 只要子类有权访问就不用反射, 可以说对运行期效率基本没有影响. 编译时速度有些影响, 但是不影响在IDE中开发时的自动提示, 重构和其它辅助功能, 编译上稍微多花点时间应该可以接受吧, 换来的是运行期比Hibernate快几倍到上千倍的效率.

robbin 写道

附件是完整的RoR版本的项目示例代码。要运行它,需要安装MySQL数据库(InnoDB表类型),Ruby和Ruby on rails环境。在MySQL数据库中分别创建demo数据库和demo_test数据库,修改demo\config\database.yml中的MySQL数据库配置,改成你的数据库密码。然后在项目跟目录下面执行:
rake db:migrate
rake db:test:clone_structure
rake test
即创建开发环境数据库,创建测试环境数据库,和执行所有的单元测试。领域模型代码位于demo\app\models目录下面;单元测试代码位于demo\test\units目录下面

用RoR数据库还要自己建, 这点我自认TOB做得更好, 只要配置好连接参数, 运行期TOB会自动创建或者扩充数据库表结构, 应用开发人员只需要创建和修改Java源码, 编译后直接运行就可以了.
36 楼 robbin 2007-03-04  
fuliang 写道
我感觉java实现充血型模型有难度关键是:
一方面,如果使用ioc,则由于entity bean是不受ioc管理.
另一方面,Java实现的domain如果能够象ror的domain继承类似于ActiveRecord那样的来实现持久化,就会向ejb那样被人指责
依赖于具体的框架,具有不可携性,很难移植...
而rails则不会,因为ruby只有rails,没有形成真正的平台,况且rails足够好,框架的侵入性没有什么不可接受的.


Java难于实现充血模型的根本原因还是在于:Java是静态类型的语言,难以运行期任意的动态改变其行为,所以必须依赖外部容器例如IoC进行对象依赖组装,也必须依赖特定的ORM框架进行增强其行为,这些容器和框架本质上都是通过动态代理方式来增强类,其结果就是对象的设计必须符合容器对它的要求,从而限制你追求理论上更完美模型的可能性。至于继承不继承类,这个根本无关紧要。

不知道大家有没有想过,为什么Java这么强调面向接口编程?面向接口编程为什么对Java这么重要?但是对于动态面向对象语言ruby来说,却根本不需要接口这种概念。这是因为在Java中是类型决定行为,所以类型的地位很重要,你一继承,对象的行为就被限制死了,所以Java很忌讳继承的使用;但是ruby的类型不决定行为,所以随便你怎么继承,也不会限制对象的行为。

技术的进步会影响到理论的实现和普及。在Java世界ORM流行之前,要对持久层进行对象建模,根本不切实际。我在2003年之前都是采取类似iBATIS的方式建模。

03年ORM开始流行,自从ORM框架逐渐成熟以后,人们可以开始在持久层进行对象建模了,这个时候Martin Fowler又说你们的模型是贫血的,必须给模型充血。04年的时候老马这么一说,着实让我们烦躁了一阵。你说要充血,可我们手里根本就没有输血的工具阿,何况我们贫血模型也用得挺好阿,干吗要充血?

05年以后RoR开始逐渐被人关注。这个时候我们发现原来RoR才是真正适合充血模型的工具。在RoR的支持下,充血模型果然可以玩的有声有色,所以我们也开始逐渐接受充血。

35 楼 jamesby 2007-03-04  
前面有一篇关于充血模型还是涨血模型的讨论我也看了,涨了不少见识. 感谢各位的精彩讨论.
34 楼 agile_boy 2007-03-04  
如果单从语言层面上看,我觉得两者没有什么可比性,两者都是比较好的OO语言,不过ruby可能更灵活更动态而已。
在实现Domain model上,ruby也是借助于rails(对ror还不是很了解),那么java借助于hibernate/jdo来实现这样的模型应该也不是什么大问题
33 楼 jianfeng008cn 2007-03-03  
再放一箭 楼上的朋友说话和其照片让我感觉很相辅! 

多谢robin等的耐心讲解,thinking
32 楼 newman 2007-03-03  
昨天晚上就为这个话题在网上逗留了许久,今天再一看发现robbin同学很是快手,把这个话题又重新整理了一遍,真是辛苦,虽然争论依然激烈,不过很多问题也得到了澄清,看着各位大侠在场上刀来剑往,我想在这里说上几句:
1.这个问题的来源是fatzhen发的一个名为"主题:   为什么java里不能把域对象和DAO合并,rails里面就可以?",原贴子的地址是http://www.iteye.com/topic/56949。
2.在这篇贴子里,robbin还提到了另一篇精彩的文章叫“完美就是生产力”,一位老兄在半夜挑灯夜战抽烟搞出来的一篇文章,我建议参与讨论的网友如果对ruby不够了解的去看看,我看了后是很有收获的,很多背景问题(因为我是搞java的,rr只是搞了些皮毛)能搞清楚。
3.讨论的问题还是域对象模型在两种语言中的支持和实现优劣,而不是某某要取代某某。
4.域模型比oo模型要高级,对业务的描述性更好,也利于业务的计算实现,rr对域模型的支持和实现我认为是要优于java,但是,java也未必需要如rr一般的方法去实现域对象模型,正好比一个使刀的,一个用剑的,没必要说非得弃剑用刀或者弃刀用剑,尤其是java语言和rr语言在本质和风格上面相差太大。
5.代码强阅读性和LOC少是rr的最大热点,当然ActiveRecord做得也是非常不错,但是Java同样有很多出色的优点。
6.贫血模型还是涨血模型,我看还是根据实际应用来论,robbin也对这个问题做了分析,我也不多说了,我认为分析得还是很到位。
7.既然是刀来剑往,我想没有一个人能够100%保持彬彬有礼的形象,出言不逊在所难免,但是既然都是武林中人,能够互相切磋技艺心法,实在是人生之幸事,那些激昂言语也大可在一笑中抛诸脑后。
31 楼 clamp 2007-03-03  
很漂亮的实现,不过仍然有问题。

1.kind只是一个字典表,而现在却被扩充为很庞大的DomainModel,这个从业务分析的角度来说是不太自然的

2.processing_task这个业务逻辑已经在user,task,kind这三个类中都出现了,这样做是否合理?是否可以重构?重构以后是否会破坏DomainModel?

3.指定用户user的统计当月总的任务数,已完成任务数,未完成任务数
all_tasks, processed_tasks, processing_tasks = kind.tasks.current_month_tasks(user) 
这个为什么是kind的领域逻辑而不是user的领域逻辑?
比如写成user.tasks.current_month_tasks(kind)
 
越复杂的关系运算就越难归结为某个DomainModel的领域逻辑,虽然ruby在这点上比java强,但是强的也有限。






30 楼 fuliang 2007-03-03  
我感觉java实现充血型模型有难度关键是:
一方面,如果使用ioc,则由于entity bean是不受ioc管理.
另一方面,Java实现的domain如果能够象ror的domain继承类似于ActiveRecord那样的来实现持久化,就会向ejb那样被人指责
依赖于具体的框架,具有不可携性,很难移植...
而rails则不会,因为ruby只有rails,没有形成真正的平台,况且rails足够好,框架的侵入性没有什么不可接受的.
29 楼 robbin 2007-03-03  
见主贴贴
28 楼 JavaInActoin 2007-03-03  
这里是讨论问题,不是开发一个可运行的软件,没有人真的把这些代码下载放在项目里跑,也就看看思想罢了,总共就几十行代码,作为附件上传看起来也不方便。
27 楼 robbin 2007-03-03  
JavaInActoin 写道
robbin 写道

你这个领域模型是根本跑不起来的。数据库根本就没有department这个表,你的department的users属性根本就是null,一跑就会出错。你的user.addTask方法也执行不了,没有Dao的支持,你再调用addTask,数据库里面也不增加记录。UserManager也不应该存在,这是属于user的domain logic。
请不要拿一个根本不能运行的错误代码出来,请先在你本地搭建一个实际的web项目,自己测试通过了,再贴出来。

单独的领域模型当然跑不起来,和其它层装配起来就跑的很以欢畅了。
我写的Domain Model是根据Eric Evans的观点来的,很多持久化(包括事务)的操作超越了业务逻辑,需要被安排在应用服务层。
你写的那段不是MF的充血模型,而是事务脚本。
robbin 写道

请不要拿一个根本不能运行的错误代码出来,请先在你本地搭建一个实际的web项目,自己测试通过了,再贴出来。

这个不是讨论问题的最佳方法,太累了,你写的代码同样不能运行
robbin 写道

    public employee(String username, String department) {   


寻找这样的错误是没有意义的,只要思路正确,在座的各位都可以把代码调试好。


我写的RoR充血模型代码放在项目里面立刻可以跑的。至于你所谓的和其他层装配起来就可以跑的很欢畅,那么请你把你的代码和其他层装配好,然后作为附件上传,请大家来下载测试一下你的代码究竟能不能跑!你写了一个根本在实际项目中不能用的代码出来,能说明什么问题呢?
26 楼 JavaInActoin 2007-03-03  
robbin 写道

你这个领域模型是根本跑不起来的。数据库根本就没有department这个表,你的department的users属性根本就是null,一跑就会出错。你的user.addTask方法也执行不了,没有Dao的支持,你再调用addTask,数据库里面也不增加记录。UserManager也不应该存在,这是属于user的domain logic。
请不要拿一个根本不能运行的错误代码出来,请先在你本地搭建一个实际的web项目,自己测试通过了,再贴出来。

单独的领域模型当然跑不起来,和其它层装配起来就跑的很以欢畅了。
我写的Domain Model是根据Eric Evans的观点来的,很多持久化(包括事务)的操作超越了业务逻辑,需要被安排在应用服务层。
你写的那段不是MF的充血模型,而是事务脚本。
robbin 写道

请不要拿一个根本不能运行的错误代码出来,请先在你本地搭建一个实际的web项目,自己测试通过了,再贴出来。

这个不是讨论问题的最佳方法,太累了,你写的代码同样不能运行
robbin 写道

    public employee(String username, String department) {   


寻找这样的错误是没有意义的,只要思路正确,在座的各位都可以把代码调试好。

相关推荐

    Domain model manual

    通常,领域模型包含了业务实体(Entities)、值对象(Value Objects)、聚合(Aggregates)、领域事件(Domain Events)、服务(Services)以及领域驱动设计(DDD)中的其他元素。 1. **业务实体(Entities)**:...

    Python库 | domainmodel-0.12.tar.gz

    "domainmodel-0.12.tar.gz" 是一个针对Python的特定库,名为"domainmodel",版本号为0.12。这个库很可能包含了特定领域的数据模型和业务逻辑,方便开发者进行结构化编程和领域驱动设计。 "domainmodel"库可能包含...

    Python库 | domainmodel-0.2-py2.4.egg

    python库。 资源全名:domainmodel-0.2-py2.4.egg

    lec-5 领域模型 DomainModel.ppt

    领域模型 DomainModel 领域模型是软件设计中的一种重要概念,它旨在理解系统如何工作,包括内部行为和外部行为。领域模型的目的是为了确定系统中各个元素之间的交互关系,以便产生外部行为。 领域模型为什么重要?...

    Domainmodel:XText Domainmodel示例(按发行版)

    在"XText Domainmodel示例(按发行版)"这个项目中,我们可以推测这是一系列按照不同版本组织的示例,展示了如何使用XText来创建和管理领域模型。XText通过其强大的语法定义能力,允许开发者定义自己的领域模型语言...

    Domain Model - The Theory, The Reality, The Dream

    **领域模型(Domain Model)——理论、现实与梦想** 领域模型是软件开发中的核心概念,尤其是在面向对象设计和企业级应用开发中。它是一个反映业务领域的抽象模型,包含了业务规则、实体、值对象、聚合、服务等关键...

    探索DomainModel系列

    MapperRegistry是工厂方法的变形?摘要本文通过由ActiveRecord模式到DataMapper模式(使用工厂方法)再到DataMapper模式(使用MapperRegistry)的一系列重构,探讨模式背后隐藏的思想和面向对象设计原则。...

    Java MVC framework, agile, fast, rich domain model, made e.zip

    "fast"和"rich domain model"可能是在强调Java MVC框架在处理复杂业务逻辑时的高效性能和强大的领域模型支持。领域模型是业务对象在软件中的表示,它封装了业务规则和数据。一个丰富的领域模型可以帮助开发者更好地...

    corpis-invoice-domain-model-1.2.1.jar

    jar包,官方版本,自测可用

    Xen如何创建DomainU

    /* 在这里启动 device-model */ 创建块设备界面(); /* Create the block device interface (blkif) for the vm. The vm needs a blkif even if it doesn't have any disks at creation time */ } ``` 3. 主函数: ...

    Optimal Transport for Domain Adaptation

    propose a regularized unsupervised optimal transportation model to perform the alignment of the representations in the source and target domains. We learn a transportation plan matching both PDFs, ...

    Domain Generalization A Survey.pdf

    最后,我们将对Domain Generalization的未来研究方向进行讨论和展望。 Domain Generalization的应用前景非常广阔。例如,在计算机视觉中,Domain Generalization可以应用于物体识别、图像分割、动作识别、人脸识别...

    领域驱动(DDD)充血模式下,domain 与 Service以及Repository的解耦---DOMAIN EVENT

    首先,我们来理解DDD的核心概念——领域模型(Domain Model)。领域模型是业务逻辑的抽象表示,它包含了业务领域的实体(Entities)、值对象(Value Objects)、领域服务(Domain Services)和仓储(Repositories)...

    Applying Domain-Driven Design and Patterns: With Examples in C# and .NET

    The main focus of the book is how a Domain Model could be constructed to be clean, yet still be persistence-friendly. It shows what the persistence solution could look like for such a Domain Model and...

    techniques of model-based control

    Continuous time modeling: time domain, Laplace domain, and FOPDT models Feedforward, cascade, override, and single-variable inferential control approaches One and two degree of freedom Internal ...

Global site tag (gtag.js) - Google Analytics