对充血模型的疑问

问题描述

小弟我在坛子上看到关于贫血模型和充血模型的讨论后一直再想这对于我这种代码小工意味着啥?是否可以更快更迅速更敏捷的完成代码完成开发。一直做的项目都是SSH 然后分层 action,service,dao,entity;有时候我觉得dao层没什么必要啊,既然hibernate是面向对象为何还要 dao.save(entity) dao.update(entity) 这样操作?感觉如果去掉dao层 直接entity.update(),entity.delete(); 这样是否会更形象?然后小弟开始尝试,首先搭了个struts2+spring3+Hibernate3.6的ssh工程用的是全注解搭法这样开发就不用写配置文件了还是相当的爽啊首先我觉得应该有一个公共的类充当所有entity的父类import java.beans.PropertyDescriptor;import java.io.Serializable;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.HashMap;import javax.annotation.Resource;import org.hibernate.SessionFactory;import org.springframework.beans.BeanUtils;import org.springframework.orm.hibernate3.HibernateTemplate;import org.springframework.stereotype.Repository;@Repository("MagicH")public class MagicH extends HibernateTemplate {@Resource(name = "sessionFactory")public void setSuperSessionFactory(SessionFactory sessionFactory) {super.setSessionFactory(sessionFactory);}private Serializable id; // 标示private Class clazz; // 实体private Object entity; // 数据库实体private PropertyDescriptor targetPds[]; //初始化后属性private HashMap setMethodMap = new HashMap(); //set方法映射private HashMap getMethodMap = new HashMap(); //get方法映射/** * 模型初始化 * * @param clazz * @param id */public boolean init(Class clazz, Serializable id) {this.id = id;this.clazz = clazz;PropertyDescriptor targetPds[] = BeanUtils.getPropertyDescriptors(clazz); for (PropertyDescriptor pdObj : targetPds) { setMethodMap.put(pdObj.getName().toLowerCase(), pdObj.getWriteMethod()); getMethodMap.put(pdObj.getName().toLowerCase(), pdObj.getReadMethod()); } this.entity = get(clazz, id);return this.entity==null?false:true; }/** * 获取对象实体 * * @return */public Object getObj() {if (entity == null) {this.entity = get(clazz, id);}return entity;}/** * 删除对象实体 */public void delObj() {if (entity != null)delete(entity);elsedelete(get(clazz, id));}/** * 设置数据库实体属性 * @param propertyName * @param propertyValue */public void setProperty(String propertyName, Object propertyValue) { Method writeMethod = (Method) setMethodMap.get(propertyName.toLowerCase()); try {writeMethod.invoke(entity, new Object[] {propertyValue});} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/** * 获取属性的值 * @param propertyName * @return */public Object getPropertyValue(String propertyName){Method readMethod = (Method)getMethodMap.get(propertyName.toLowerCase());Object returnValue = null;try {returnValue = readMethod.invoke(entity,null);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}return returnValue;}/** * 更新对象 */public void updateObj(){update(entity);}/** * 保存对象 * @param obj * @return */public Serializable addObj(Object obj){Serializable id = save(obj);init(obj.getClass(),id); return id;}}建立一张用户表测试,对应实体如下import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;import org.hibernate.annotations.GenericGenerator;import org.springframework.stereotype.Repository;import com.usoft.core.dao.impl.MagicH;/** * MagicUser entity. @author MyEclipse Persistence Tools */@Repository("MagicUser")@Entity@Table(name = "MAGIC_USER")public class MagicUser extends MagicH implements java.io.Serializable {// Fieldsprivate String userId;private String userNam;private String userSex;private String userPhone;// Constructors/** default constructor */public MagicUser() {}/** full constructor */public MagicUser(String userNam, String userSex, String userPhone) {this.userNam = userNam;this.userSex = userSex;this.userPhone = userPhone;}// Property accessors@GenericGenerator(name = "generator", strategy = "uuid.hex")@Id@GeneratedValue(generator = "generator")@Column(name = "USER_ID", unique = true, nullable = false, length = 32)public String getUserId() {return this.userId;}public void setUserId(String userId) {this.userId = userId;}@Column(name = "USER_NAM", length = 500)public String getUserNam() {return this.userNam;}public void setUserNam(String userNam) {this.userNam = userNam;}@Column(name = "USER_SEX", length = 1)public String getUserSex() {return this.userSex;}public void setUserSex(String userSex) {this.userSex = userSex;}@Column(name = "USER_PHONE", length = 11)public String getUserPhone() {return this.userPhone;}public void setUserPhone(String userPhone) {this.userPhone = userPhone;}}这是本人测试用的serviceimport javax.annotation.Resource;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;import com.usoft.magich.bs.ImagicServiceTest;import com.usoft.magich.vo.MagicUser;@Service("MagicService")@Transactional(readOnly = false, propagation = Propagation.REQUIRED)public class MagicServiceTestImpl implements ImagicServiceTest { @Resource private MagicUser magicUser;public void testMagicH() {//保存magicUser.setUserNam("用户123");magicUser.setUserPhone("12345");magicUser.setUserSex("1");magicUser.addObj(magicUser); //更新magicUser.setProperty("UserNam", "1234567");magicUser.updateObj();System.out.print(magicUser.getPropertyValue("UserNam"));boolean b1 = magicUser.init(magicUser.getClass(), "aaa"); //id 不存在初始化失败System.out.println(b1);boolean b2 = magicUser.init(magicUser.getClass(),"402881862da6ec3b012da6fb4f640004"); //id存在为 trueSystem.out.println(b2);magicUser.delObj(); //删除 对象}}只是中午吃饭时脑子那么想了一下,然后回来就尝试写了个单表的增删改查,我个人举得无论是单表还是多表最后数据库查出来的无非是个二叉表,而其中的一条记录应该对应一个java类 多条记录则是该java类的List集合,然后所有的数据库操作不再是dao.doSomething 而是entity.doSomething我这样做了后写的代码就只有actiong,service,entity层了,不知道这样是否可行,谁能解释一下我的疑问。问题补充看了大家的回复深受启发,感觉自己这个想法似乎不可取就不再钻牛角尖了。可能一直处于开发人员的角色,所以关系的核心问题无非就是 写最少的代码做最多的事

解决方案

一个问题的作用域将决定一个问题的解决方案是否合适。其实这也是大多数人对于领域模型各种变种的误解。当一个简单类具备了field和method之后,大师们告诉你,这个类的实例叫做对象,基于这种方式写出来的程序叫OO。大师们还告诉你,只有field和它们对应的setter/getter方法的类,不怎么OO,因为这叫贫血。在类上加上method,赋予类逻辑执行能力,这叫领域模型,比较OO。恩,我们不妨考虑一个拥有3000w行代码的大系统,假设它需要1000个领域模型类。这相当于把一个最简单的问题放大了1000倍,那么我们等于把我们的逻辑重复1000遍。当然,这个系统的逻辑不再是增删改查那么简单,而是有复杂的业务流程。这个时候,你会发现,一个领域模型类可能将达到20K,甚至30K那么大。里面可能有超过40个method,对应30种不同的业务流程。某天,项目经理说,hey,小伙子,客户说这业务改了,它们要在所有涉及到数据库保存的地方加条日志,并通知另外一个系统。想象一下你的工作?在一个超过2000行的类里面,找到那些方法,一个个加过来。恩,这就是专家们说的,这很OO。
解决方案二:
lz的代码是个反例,正因为如此,才显得有意义!
解决方案三:
这样的贴子被管理员从论坛拿到这,真是悲哀!
解决方案四:
downpour 写道一个问题的作用域将决定一个问题的解决方案是否合适。其实这也是大多数人对于领域模型各种变种的误解。当一个简单类具备了field和method之后,大师们告诉你,这个类的实例叫做对象,基于这种方式写出来的程序叫OO。大师们还告诉你,只有field和它们对应的setter/getter方法的类,不怎么OO,因为这叫贫血。在类上加上method,赋予类逻辑执行能力,这叫领域模型,比较OO。恩,我们不妨考虑一个拥有3000w行代码的大系统,假设它需要1000个领域模型类。这相当于把一个最简单的问题放大了1000倍,那么我们等于把我们的逻辑重复1000遍。当然,这个系统的逻辑不再是增删改查那么简单,而是有复杂的业务流程。这个时候,你会发现,一个领域模型类可能将达到20K,甚至30K那么大。里面可能有超过40个method,对应30种不同的业务流程。某天,项目经理说,hey,小伙子,客户说这业务改了,它们要在所有涉及到数据库保存的地方加条日志,并通知另外一个系统。想象一下你的工作?在一个超过2000行的类里面,找到那些方法,一个个加过来。恩,这就是专家们说的,这很OO。没看懂。你的意思是多一个领域对象就把问题放大一倍?为什么会有这样的结论?充血与贫血 的差别我认为主要是:一个是按功能分解业务逻缉一个是按对象分解业务逻缉后者带来的是细粒度的逻缉划分,从而会避免重复代码,并使得业务逻缉可以被重用。引用第一,我的观点一向是使用Java语言就不要谈什么充血模型。因为Java语言从语法角度对于逻辑的高度抽象性就不够,很容易就造成一个类的急速膨胀。 java不能充血不能认同。那只是说对于现在涉及到数据库的应用吧。致少仅在内存中完成的逻缉,用java做到OO是没问题的。比如:ArrayList这样的类就是充血的。java的语法少了什么呢?另外lz的做法目标是好的,可是做出来的代码却让MagicUser变得难以理解。MagicUser本身是一个持久化对象。MagicH却给它加了一些和子类重叠的属性以及Dao的逻缉。MagicH和MagicUser是硬给拼到一块的。当面对一个MagicUser,是该用父类的方法,还是子类的方法呢?MagicH起到的作用就是把MagicUser搞乱,而不是让MagicUser充血!
解决方案五:
JasonChow 写道这种模式应该是"活动记录(active record)"。他比事务脚本模式要更能体现领域模型的一些特点,但是随着业务的复杂度提升,不可避免的要和持久层耦合的更强,最好的是在ORM的帮助下实现领域模型和仓库的分离,这对团队的要求比较高,领域驱动在某些特别的情况下也可以在局部使用事务脚本,来弥补一下天然阻抗。最后借用书里的一句话,使用何种模式驱动,要看项目和团队实力的实际情况,使用事务脚本总比项目失败要好吧。引用使用何种模式驱动,要看项目和团队实力的实际情况,使用事务脚本总比项目失败要好吧。为什么使用事务脚本就会有失败的导向?项目失不失败和这个有什么关系?
解决方案六:
楼主你确定你了解所谓的领域模型?
解决方案七:
这种模式应该是"活动记录(active record)"。他比事务脚本模式要更能体现领域模型的一些特点,但是随着业务的复杂度提升,不可避免的要和持久层耦合的更强,最好的是在ORM的帮助下实现领域模型和仓库的分离,这对团队的要求比较高,领域驱动在某些特别的情况下也可以在局部使用事务脚本,来弥补一下天然阻抗。最后借用书里的一句话,使用何种模式驱动,要看项目和团队实力的实际情况,使用事务脚本总比项目失败要好吧。
解决方案八:
不要MagicUser extends MagicH把MagicUser作为MagicH的内部类,这样MagicUser可以自由new
解决方案九:
lss的orm写的不错哈。最近也在搞scala---补充lz的问题,正如ls所说的,在java里面就别讨论充血。
解决方案十:
第一,我的观点一向是使用Java语言就不要谈什么充血模型。因为Java语言从语法角度对于逻辑的高度抽象性就不够,很容易就造成一个类的急速膨胀。第二,我们总是生活在一个充满着最佳实践的世界。如果说把逻辑封装在实体模型中是一条最佳实践,那么让一个类不超过8k就是另外一条最佳实践。当2条最佳实践发生矛盾的时候,必须根据最佳实践的优先级和重要性调整编程思路。这也就是每个程序员在哲学选择上不同的分歧所在。
解决方案十一:
downpour 写道一个问题的作用域将决定一个问题的解决方案是否合适。其实这也是大多数人对于领域模型各种变种的误解。当一个简单类具备了field和method之后,大师们告诉你,这个类的实例叫做对象,基于这种方式写出来的程序叫OO。大师们还告诉你,只有field和它们对应的setter/getter方法的类,不怎么OO,因为这叫贫血。在类上加上method,赋予类逻辑执行能力,这叫领域模型,比较OO。恩,我们不妨考虑一个拥有3000w行代码的大系统,假设它需要1000个领域模型类。这相当于把一个最简单的问题放大了1000倍,那么我们等于把我们的逻辑重复1000遍。当然,这个系统的逻辑不再是增删改查那么简单,而是有复杂的业务流程。这个时候,你会发现,一个领域模型类可能将达到20K,甚至30K那么大。里面可能有超过40个method,对应30种不同的业务流程。某天,项目经理说,hey,小伙子,客户说这业务改了,它们要在所有涉及到数据库保存的地方加条日志,并通知另外一个系统。想象一下你的工作?在一个超过2000行的类里面,找到那些方法,一个个加过来。恩,这就是专家们说的,这很OO。为什么"一个领域模型类可能将达到20K,甚至30K那么大。里面可能有超过40个method,对应30种不同的业务流程。"?为什么不能通过继承等方式对公共功能进行抽象和重用?或者,如果这些逻辑根本就不该重用的话,充血模型和贫血模型的唯一区别就成了:是领域模型类达到20K,还是DAO类达到20K。关于充血贫血模型的讨论,该说的话04年前后大佬们都已说透了,然而对于一些善于思考的新人,领导说编程规范就是这样,被强制灌输思想的时候,或者对于那些还在这个领域奋斗的理想主义者来说,困扰并没有消除。这种困扰从表面上看是不确定业务逻辑放到哪儿,如何定义类的职责边界,深层问题则是能不能最大可能的进行封装和重用,而这一点除了受限于设计能力、方法论等因素之外,还强烈受制于所处的环境和工具集。从我近几年使用ruby on rails的体会看,之所以java论坛还在纠结充血贫血,正因为大家用的是java。从实现角度来看,只靠java所谓的OO,“继承”、“多态”那么几板斧,并不能把所有概念都能很好的抽象、封装起来。既然做不好,那就干脆点,把那些持久层相关的功能完全隔离出来,定个概念叫DAO,放在一个地儿管,一样看着清爽。我承认这是某种程度的“务实”。然而这种状况就像徐^贲再议知识分子里描述的那样:"是现实使然的“不得不如此”(necessity),而不是取决于自由意志的“我选择如此”(choice)"。"长期的思想禁锢使得知识分子习惯于把“不得不如此”当成是“我选择如此”。"(这个回贴要是让R同学看到,肯定又睡不着觉了)我最近正好用scala试写了一个orm库,在这里拿出来给大家秀一下,并提起一个新的话题:“如果换一个理想工具的话,忘掉充血贫血的纷争,重新聚焦在抽象和封装上,你想做到怎样的效果才比较理想”,-- 然后再回过头反思,如果你用java,能不能做出同等效果的类库。甚至可以考虑有没有折衷的办法,成本收益,务实的做法,等等。我这个orm库模仿了rails3 ActiveRecord的API,重点参考了squeryl的源码,还远到不了可用的程度,也没有长远的计划,只是一时兴趣。先上使用范例吧。https://github.com/liusong1111/soupy/blob/master/app/models/User.scala定义model和DAO。在DAO里写几个自定义的方法。package modelsimport soupy.persistence._import reflect.BeanInfoimport util.Random//定义users表里的三个字段。//trait相当于java的interface。后面定义的model和dao都混入了它。trait UserDef extends TableDef { var id = field(IntType, "id") var name = field(StringType, "name") var age = field(IntType, "age")}//定义Model类,编译出的User.class里会生成String name,int age等属性和对应的get/set方法@BeanInfoclass User extends Model with UserDef {}//定义Dao类(误命名成schema了),编译时会生成StringProperty name, IntProperty age等属性(你可以当成常量),另外父类中有insert,update,count,where等大量方法可以直接用。//对应表名"users"class UserSchema extends Schema[User, UserSchema]("users") with UserDef { //主键是id(现在做的还不完善) val idProperty = IdProperty(id) // 按名字查询,返回一个query对象。后面会演示query对象的具体用法,跟rails3相近,有where、order、limit、group、offset、limit等方法,另外还有两个重要的方法all和first,分别返回List<User>和User,调用这两个方法时会执行相应的sql语句。 // query可以是链式(chainable)的,甚到是DAO级别的chainable,后面范例中可以看到。 def byName(name: String) = where(User.name == name) // 找出年轻人 def youngs = { where(age < 18) } // 找出姓刘的 def liu = { where(name like "%liu%") }}//User是DAO的单例对象,直接使用这个对象。object User extends UserSchemaModel类和DAO可以这样使用:object Main { def main(args: Array[String]) { //设定数据库连接 Repository.setup("default", Map("adapter" -> "mysql", "host" -> "localhost", "database" -> "soupy", "user" -> "root", "password" -> "")) //为了好玩,user.age每次赋给一个随机数 val rand = new Random // 打印出总记录数,后台会执行 select count(1) from users,你懂得 // count是DAO父类的方法 println("-- count before create:" + User.count) //创建,同样insert是DAO父类封装的方法。同时提醒一下,它是强类型的,即,如果你往User.insert里传一个new Animal()进去编译会通不过的。 var user = new User() user.name = "sliu" user.age = rand.nextInt(70) User.insert(user) // 再打印一下看看 println("-- count after create:" + User.count) //更新:(这块功能还没做完) user.age = rand.nextInt(70) User.update(user) //删除 //User.delete(user) //查询,重头戏了! println("-- normal query --") //where方法可以串着写(chainable) //最后到all方法时会执行select users.id,users.name,users.age from users where name like 'liu%' AND age > 18 //all会返回List<User> var users = User.where(User.name like "liu%").where(User.age > 18).all //遍历一下看看 users.foreach { user => println("name:" + user.name + " age:" + user.age) } //更酷的来了! //找到姓刘的年轻人,而且年纪在10岁以上的前两个人。 //youngs和liu是我们在UserDAO里自定义的方法,也是chainable的~ println("-- [COOL] use DAO's selector chain --") users = User.youngs.liu.where(User.age > 10).limit(2).all users.foreach { user => println("name:" + user.name + " age:" + user.age) } //当然,你可以直接遍历所有年轻人: User.youngs.all,它会执行什么样的SQL你了解 //找到id为1的User //你可以认为它返回的是一个User对象。实际上它返回的是Option[User]类型,这是scala为了防止NullPointerException引入的一个概念,大家可以忽略。 println("-- first --") var user1 = User.where(User.id == 1).first if (user1.isEmpty) { println("not found") } else { println(user1.get) } //在Query上可以怎么玩? //More Details on Query ------- // where clause //User.age是一个IntProperty对象(注意,你可以把它看成静态变量),User.age > 33的值不是boolean,而是一个Query实例,这个query有个toSQL方法,返回 "age > 33"这个串。为了省事,我把它的toString方法也覆写成toSQL了。 println(User.age > 33) // age = 33 println(User.age == 33) // name > 'liusong' println(User.name > "liusong") // name = 'liusong' println(User.name == "liusong") // name like 'liu%' // 注意:你如果写这样的代码User.age like "liu%"会编译不过,因为User.age是IntProperty对象,它没有like方法。同时,如果like后面跟的不是String也会编译不通过。 println(User.name like "liu%") //AND条件 //name = 'liusong' AND age > 28 println((User.name == "liusong").where(User.age > 28)) // 跟前面效果一样 println(User.name == "liusong" && User.age > 28) // 既有AND又有OR //(name = 'liusong' AND age > 28) OR age < 10 OR name like 'liu%' println(User.name == "liusong" && User.age > 28 || User.age < 10 || (User.name like "liu%")) //用括号调整AND、OR的分组 //(name = 'liusong' AND (age > 28 OR age < 10)) OR name like 'liu%' println(User.name == "liusong" && (User.age > 28 || User.age < 10) || (User.name like "liu%")) // 指定order by,group等部分 println(User.where(User.age > 28).where(User.name like "liu%").order(User.name.desc).group("group by name")) //内部实现 // look into properties println("-- look into properties --") User.properties.foreach { prop => println(prop.name) } // use singleton object's build // same as `new User` println("-- singleton's `build` --") val u = User.build println(u.name + u.age) //you can use reflect style but type safe like this: User.name.set(m, "sliu") println("-- set/get property using type safe reflection --") User.name.set(user, "another name") println(User.name.get(user)) println("-- use Query object directly --") //select * //from users //where name = 'sliu' AND age > 30 //group by age println(new Query("users").where(User.name == "sliu").where(User.age > 30).group("group by age").order(User.age.desc)) }}这个类库的实现代码:https://github.com/liusong1111/soupy/blob/master/src/soupy/persistence.scala特色有三个:一:在一个地方声明字段列表,就做到了给model和dao分别生成两组属性,分别用来接收数据和生成sql。(类比java类的属性和一些静态变量) 举例:(new User()).name是String类型,User.name是StringProperty类型,所以可以写成User.name like "liu%",但不能写成(new User()).name like "liu%",编译通不过,因为like方法是StringProperty的,String里没有。 这个效果我觉得是我这个小类库的特色,我个人认为这是使用scala来跨越java限制的一个例证。在java里,即使考虑用javaassist、aspectj、Annotation Process Tool、dynamic proxy等工具,也很难达到同样的效果。我是使用scala的abstract type辅以Manifest做到的,其实它的内部实现还有简化的空间。二:chainable:这是借助scala的case class和一些花活做到的。三:类型安全:这是借助scala强大的类型系统(包括泛型等)做到的,比如,你不需要进行强制类型转化,User.where(...).all返回给你的就是List<User>,不是List<Object>。做这个小东西主要是学习scala。我个人最近比较看好scala语言。scala是静态语言,所以有编译期检查的优势,它和java集成极佳,它编译成java字节码(.class文件)在jvm上跑。可以和java代码互相调用(无论是jdk的库、开源的库还是自己写的某个java文件或整个java工程)。它编译出的字节码性能上接近java(考虑到尾递归优化一类的因素有些时候还可以优于java),理论上IDE的支持可以达到java的水平(目前我用intellij IDEA的scala插件感觉进步很快)。它强大的语法特性更是一时半会说不完的。当然,它还没走入主流,它同样面临着当年ruby面临的一些质疑,比如学习曲线一类的,把它引入到生产环境需要很大的勇气和控制能力。作为java程序员,我觉得有精力的话可以关注一下,它完全可以引领java语言这几年的发展方向。
解决方案十二:
downpour 写道一个问题的作用域将决定一个问题的解决方案是否合适。其实这也是大多数人对于领域模型各种变种的误解。当一个简单类具备了field和method之后,大师们告诉你,这个类的实例叫做对象,基于这种方式写出来的程序叫OO。大师们还告诉你,只有field和它们对应的setter/getter方法的类,不怎么OO,因为这叫贫血。在类上加上method,赋予类逻辑执行能力,这叫领域模型,比较OO。恩,我们不妨考虑一个拥有3000w行代码的大系统,假设它需要1000个领域模型类。这相当于把一个最简单的问题放大了1000倍,那么我们等于把我们的逻辑重复1000遍。当然,这个系统的逻辑不再是增删改查那么简单,而是有复杂的业务流程。这个时候,你会发现,一个领域模型类可能将达到20K,甚至30K那么大。里面可能有超过40个method,对应30种不同的业务流程。某天,项目经理说,hey,小伙子,客户说这业务改了,它们要在所有涉及到数据库保存的地方加条日志,并通知另外一个系统。想象一下你的工作?在一个超过2000行的类里面,找到那些方法,一个个加过来。恩,这就是专家们说的,这很OO。哈哈,这算是我目前不支持所谓充血的原因之一。
解决方案十三:
用SSH做一个应用是多么麻烦啊,要写这么多代码,长此下去,必成代码工人
解决方案十四:
为什么Rod不把HibernateTemplate定义为final类型的!
解决方案十五:
充血模型,领域驱动个人觉得最好的解决之道在于DOMAIN EVENT 的应用
其他方案:
ObjectWeb的DODS就如你想象的“充血模型”,以前改shark源码的时候接触过这个持久层框架一段时间,但不得不说,比起实体与DAO分离的“贫血模型”来说,实在是很不好用。
其他方案:
个人偏向于贫血,但是特殊业务下,如文章的图片在创建时建创UUID文件名的文件夹,删除时自动删除,== 我会在POJO中注血的
其他方案:
我不如用一个基于反射的基础数据库操作的BASEDAO<Entity T,SERAILIZAL ID> 在SERVICE层里 我自动注入这个基操作DAO,如:@ResourceBASEdao<User.class,Long> userDao;
其他方案:
你的做法,说白了就是把model层和dao层合并了,没有带来任何别的变化,这种做法不会让你的开发变得更快。此外还引入了以下问题:1.你的领域对象和Hibernate框架完全耦合2.领域对象承担了不属于它的职责,即持久化。好吧,或许你会说“持久化”也可以算它的职责,那么至少“写入数据库”不是它的职责,为了剥离这个职责,演化之后你还是需要一个DAO层。3.从第2个问题就衍生出第3个问题,你知道有些领域对象是不需要持久化的,只在内存中,但按照你这个框架来的话,随随便便就要抛exception
其他方案:
你这个MagicUser类无法作为模型,因为他无法通过new的方式创建。
其他方案:
哈哈,你这个Entity充血的解释比较有意思。你这种做法,我们几年前的时候就这样做了,你那个Entity类只不过是个Dao的基类,提供了通用的增删改查改功。这并不是什么充血模型,至多算伪充血,还容易误导人概念。我觉得Entity名字换成BaseDao名比较好。充血模型更多应该从领域对象出发。

时间: 2024-08-02 09:53:07

对充血模型的疑问的相关文章

DDD~充血模型和失血模型

这几年,状态依旧不好,但在23点以后,状态还可以,所以,静下来,看点DDD,并把相关信息记载一下,今天是除夕,不过,我写文章时已经是大年初一了,呵呵,外面的炮声响亮,但我的内心很平静,也许是年龄大了,对于过年的感觉也已经淡化了吧,再或许是有些事情还放不在. 任务与目标 今年的任务挺多的,目标也确实有点大,压我的有点喘不过气来,对于年未,我们是放松的,因为一年的任何已经完成,目录也已经完成,所以是放松的:但当新的一年真的到来时,意味着你要去实现今年定的目标了,我们需要紧张起来了,需要向着那个目标去

从需求出发来看关系模型与非关系模型--关系模型与非关系模型概述

自从NoSQL概念横空出世,关系数据库似乎就成了众矢之的,似乎一夜之间,关系数据库和SQL就成了低效,高成本,速度慢的数据处理模式的代名词. 在很多地方都能看到类似:"我的项目初创,应该选择什么NoSQL产品才能快速的开发?" 这样的问题.    正因有人提出这样的问题,才坚定了我把这篇文章放在了第一章的决心.主要的目标是希望借助这样一个形式,让大家能够比较清晰的认识到类似NoSQL,SchemaFree,RDBMS,CAP,BASE等等概念的本源,并了解到他们面对的主要场景,从而避免

贫血模型与领域架构模式

转载:http://mabusyao.iteye.com/blog/467704 例子 我要举的是一个银行转帐的例子,又是一个被用滥了的例子.但即使这个例子也不是自己想出来的,而是剽窃的<<POJOs in Action>>中的例子,原谅我可怜的想像力 .当钱从一个帐户转到另一个帐户时,转帐的金额不能超过第一个帐户的存款余额,余额总数不能变,钱只是从一个账户流向另一个帐户,因此它们必须在一个事务内完成,每次事务成功完成都要记录此次转帐事务,这是所有的规则.     贫血模型 我们首

Todd.log - a place to keep my thoughts on programming TF-IDF模型的概率解释

转自:http://www.cnblogs.com/weidagang2046/archive/2012/10/22/tf-idf-from-probabilistic-view.html 信息检索概述 信息检索是当前应用十分广泛的一种技术,论文检索.搜索引擎都属于信息检索的范畴.通常,人们把信息检索问题抽象为:在文档集合D上,对于由关键词w[1] ... w[k]组成的查询串q,返回一个按查询q和文档d匹配度relevance(q, d)排序的相关文档列表D'. 对于这一问题,先后出现了布尔模

一起谈.NET技术,浅谈C#中的延迟加载(3)——还原模型的业务规则

上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以实现在实体类的属性里面访问到比他高层的数据访问层).文章的最后依旧出现杯具,原因是在对模型的属性实现延迟加载之前,这个属性可能由于我们业务的需要,它并不单单是作为一个存储和读取的功能使用,而是在其get或者set的访问器中都包含这或许复杂或许简单的逻辑代码. 举例:考虑一下这个情景,我们有

浅谈C#中的延迟加载(3)——还原“.NET研究”模型的业务规则

上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以上海企业网站制作实现在实体类的属性里面访问到比他高层的数据访问层).文章的最后依旧出现杯具,原因是在对模型的属性实现延迟加载之前,这个属性可能由于我们业务的需要,它并不单单是作为一个存储和读取的功能使用,而是在其get或者set的访问器中都包含这或许复杂或许简单的逻辑代码. 举例:考虑一下

浅谈C#中的延迟加载(3)还原模型的业务规则

上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以实现在实体类的属性里面访问到比他高层的数据访问层).文章的最后依旧出现杯具,原因是在对模型的属性实现延迟加载之前,这个属性可能由于我们业务的需要,它并不单单是作为一个存储和读取的功能使用,而是在其get或者set的访问器中都包含这或许复杂或许简单的逻辑代码. 举例:考虑一下这个情景,我们有

Java面试笔试题大汇总(最全+详细答案)

声明:有人说, 有些面试题很变态,个人认为其实是因为我们基础不扎实或者没有深入.本篇文章来自一位很资深的前辈对于最近java面试题目所做的总结归纳,有170道题目 ,知识面很广 ,而且这位前辈对于每个题都自己测试给出了答案 ,如果你对某个题有疑问或者不明白,可以电脑端登录把题目复制下来然后发表评论,大家一起探讨,也可以电脑端登录后关注我给我发私信,我们一起进步! 以下内容来自这位前辈 2013年年底的时候,我看到了网上流传的一个叫做<Java面试题大全>的东西,认真的阅读了以后发现里面的很多题

领域驱动设计系列(转)

曾经参与过系统维护或是在现有系统中进行迭代开发的软件工程师们,你们是否有过这样的痛苦经历:当需要修改一个Bug的时候,面对一个类中成百上千行的代码,没有注释,千奇百怪的方法和变量名字,层层嵌套的方法调用,混乱不堪的结构,不要说准确找到Bug所在的位置,就是要清晰知道一段代码究竟是做了什么也非常困难.最终,改对了一个Bug,却多冒出N个新Bug.同样的情况,当你拿到一份新的需求,需要在现有系统中添加功能的时候,面对一行行完全过程式的代码,需要使用一个功能时,不知道是应该自己编写,还是应该寻找是否已