锁定老帖子 主题:挑战DAO模式
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-11-11
protected final List<Persistent<Contact>> contacts = new Vector<Persistent<Contact>>(); 作为tob的使用者(写业务逻辑的人)来说,不关心也不应该关心持久层实现。contacts,就应该是个List<Contact>。仅此一点,我不可能用这个产品。这个产品的方向不对。 其次,一个产品挑战一个设计模式,这不合逻辑。根本不是一个层面的东西。关公战秦琼。一个对象数据库的对手是其他对象数据库,再远一点是其他数据库。 List<Persistent<? extends Contact>> contacts = tob.querier.query(1, 1, Contact.class, ContactQ.OWNER$NAME + " = ? AND " + ContactQ.NAME + " = ?", userName, contactName); 拿一个user的contacts要这样拿?不封装起来?这不OO嘛!这年头谁家的做法不是 user.getContacts()就完事了啊,你这号称对象数据库,反倒比人家ORM还费劲呢。 |
|
返回顶楼 | |
发表时间:2006-11-12
nihongye 写道 complystill 写道 nihongye 写道 没看出来是怎样的挑战了DAO模式的
业务类上已经没有任何持久逻辑了, 并且是在没有任何DAO的情况下实现的. tob.birth(new User(userName)); tob.querier.query(1, 1, Contact.class, ContactQ.OWNER$NAME + " = ? AND " + ContactQ.NAME + " = ?", userName, contactName); birth不是做持久化吗? birth 是进行持久化没错, 不过也可以认为是创建新对象的业务逻辑, new User(userName); 肯定是必须的, 在这之后, 用任何数据库, 包括对象数据库, Cache, db4o等等, 也少不了一个 session.save(obj) 类似的逻辑的. 查询也是根据业务需要, 你指定条件, 得到持久对象的集合. 还能剔除更多持久逻辑吗? |
|
返回顶楼 | |
发表时间:2006-11-12
plato 写道 没看出来优越在哪里, 能否与Hibernate/ibatis横向比较一下, 证明所谓"业务类上已经没有任何持久逻辑了, 并且是在没有任何DAO的情况下实现的."
按我看tob不就是一个通用的DAO么? 我用hibernate也一样啊, session.save(Object), 一样的通用DAO. 创建新对象这个本身就同时兼有业务逻辑与持久逻辑的成份. 这个所有持久系统基本都需要一个上下文来指定目标存储位置. 关键是在这之后, 对象本身的读取,修改和根据关系访问相关对象的操作都在对象本身定义的方法上完成了, 甚至delete操作, 也是 Persistent<Contact> c; c.die(); 这样的语法. 而事务操作只有 startNewTransaction(); commitCurrentTransaction(); commitAllTransactions(); rollbackCurrentTransaction(); rollbackAllTransactions(); 这些可以隐含的在框架级别上进行. |
|
返回顶楼 | |
发表时间:2006-11-12
partech 写道 都需要继承你提供的TOB类,不太好吧。
很多对象数据库或ORM宣传它不需要从固定基类继承, 主要还是它们没有自己面向对象的数据模型. 数据模型是性能和开发简易性的根本解决途径, 对象数据库一直不能流行超过关系数据库, 就是模型的问题. 从公共基类继承也不全是坏事. Java类都要从Object类继承呢. |
|
返回顶楼 | |
发表时间:2006-11-12
aardvark 写道 protected final List<Persistent<Contact>> contacts = new Vector<Persistent<Contact>>(); 作为tob的使用者(写业务逻辑的人)来说,不关心也不应该关心持久层实现。contacts,就应该是个List<Contact>。仅此一点,我不可能用这个产品。这个产品的方向不对。 我的指导思想是操作持久对象的程序有权也有义务知道哪些是持久的对象, 哪些不是. 没有这个前提, 那么始终都是没有Persistent概念的OO去和非OO的Persistent系统交互. 在TOB里让应用程序自己实现相关对象的集合的逻辑, 但是并不要求应用程序去实现持久相关的部分. TOB容器通过 Collection.add(); Collection.addAll(); Collection.remove(); Collection.removeAll(); 这几个方法维护应用自己实现的集合的持久拓扑结构, 你birth一个new Contact的时候, TOB自动往当前事务版本的相应user对象的contacts集合里加入这个对象, 如果事务提交成功了, 这个版本的user连同着它的contacts集合就成为数据库的权威版本, 如果事务回滚了, 这个版本的user对象就被丢弃了, 权威版本还是原来的. 应用程序在了解这个机制的前提下, 可以自由的实现其他业务逻辑. 这其实是更好, 更灵活的逻辑分离. 引用 其次,一个产品挑战一个设计模式,这不合逻辑。根本不是一个层面的东西。关公战秦琼。一个对象数据库的对手是其他对象数据库,再远一点是其他数据库。 呵呵, 帖子是小东西, 起个名字吸引眼球而已. 说回来,真正挑战DAO的不是TOB这个产品,而是它背后面向对象的持久数据模型, TOB是这个模型的一个实际可用的实现. 引用 List<Persistent<? extends Contact>> contacts = tob.querier.query(1, 1, Contact.class, ContactQ.OWNER$NAME + " = ? AND " + ContactQ.NAME + " = ?", userName, contactName); 拿一个user的contacts要这样拿?不封装起来?这不OO嘛!这年头谁家的做法不是 user.getContacts()就完事了啊,你这号称对象数据库,反倒比人家ORM还费劲呢。 这个不是从user拿contacts的逻辑, 而是根据contact的name来查询的逻辑. 你看看它上面一段代码: System.out.println("Contacts of " + userName + " :"); for (Persistent<Contact> contact : user.o.getContacts()) { if (contactName.equals(contact.o.getName())) System.out.println(" *" + contact.o.getName()); else System.out.println(" " + contact.o.getName()); } 顶楼的代码确实没有表达出最合适的用法, 你说的这段代码改成这样再看看, 同样可以运行, 原来的写法是个bug: List<Persistent<? extends Contact>> contacts = tob.querier.query(1, 1, Contact.class, ContactQ.OWNER$ID + " = ? AND " + ContactQ.NAME + " = ?", user.getID(), contactName); 另外 TOB 可以保证不经任何配置, 未经缓存的情况下, 即便是 Persistent<User> user = tob.get(123); 这样获得来的 user, 它 user.o.getContacts(); 也能获得正确的对象集合. Hibernate里要配置点东西才行吧. |
|
返回顶楼 | |
发表时间:2006-11-12
complystill 写道 很多对象数据库或ORM宣传它不需要从固定基类继承, 主要还是它们没有自己面向对象的数据模型. 数据模型是性能和开发简易性的根本解决途径, 对象数据库一直不能流行超过关系数据库, 就是模型的问题. 从公共基类继承也不全是坏事. Java类都要从Object类继承呢. 这能比么? 人家Object是Java语言类的根基。要用java就没法不用Object。 你不成也强制人家说"要持久化,就一定要用我提供的父类,别无二法"。 即使将来OO的数据库流行起来,我相信也不会象你现在给出的实现,仅仅需要剥离OR转化的部分就是了。 采用继承父类的模式实现持久化,使我联想到,使用metaModel实现的EclipseEMF/SDO。看看象不象: public interface Book extends EObject { String getTitle(); void setTitle(String value); int getPages(); void setPages(int value); } public class BookImpl extends EObjectImpl implements Book { ... protected static final int PAGES_EDEFAULT = 0; protected int pages = PAGES_EDEFAULT; public int getPages() { return pages; } public void setPages(int newPages) { int oldPages = pages; pages = newPages; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, ..., oldPages, pages)); } ... } LibraryFactory factory = LibraryFactory.eINSTANCE; Book book = factory.createBook(); Writer writer = factory.createWriter(); writer.setName("William Shakespeare"); book.setTitle("King Lear"); book.setAuthor(writer); // Create a resource set. ResourceSet resourceSet = new ResourceSetImpl(); // Register the default resource factory -- only needed for stand-alone! resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put( Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); // Get the URI of the model file. URI fileURI = URI.createFileURI(new File("mylibrary.xmi").getAbsolutePath()); // Create a resource for this file. Resource resource = resourceSet.createResource(fileURI); // Add the book and writer objects to the contents. resource.getContents().add(book); resource.getContents().add(writer); // Save the contents of the resource to the file system. try { resource.save(Collections.EMPTY_MAP); } catch (IOException e) {} |
|
返回顶楼 | |
发表时间:2006-11-12
partech 写道 这能比么? 人家Object是Java语言类的根基。要用java就没法不用Object。 你不成也强制人家说"要持久化,就一定要用我提供的父类,别无二法"。 即使将来OO的数据库流行起来,我相信也不会象你现在给出的实现,仅仅需要剥离OR转化的部分就是了。 O的转化和映射是很自然和简单的, 关键的问题在R. 如果不是基于一定的固有模型, OO上出不来R的形式的, 这也是现有OODB都没有解决的问题. 要用面向对象的持久, 就没法不用一个持久的Relation基类. partech 写道 采用继承父类的模式实现持久化,使我联想到,使用metaModel实现的EclipseEMF/SDO。看看象不象: ... public class BookImpl extends EObjectImpl implements Book { ... protected static final int PAGES_EDEFAULT = 0; protected int pages = PAGES_EDEFAULT; public int getPages() { return pages; } public void setPages(int newPages) { int oldPages = pages; pages = newPages; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, ..., oldPages, pages)); } ... } BookImpl 是应用程序自己写么? setPages(int); 里的逻辑没怎么看懂? 是业务逻辑还是持久逻辑? 另外没有见到Book和Writer互取的写法, 从一个Book获得Writer, 或者反过来要怎么搞的? 还有查询怎么支持的? |
|
返回顶楼 | |
发表时间:2006-11-12
complystill 写道 顶楼的代码确实没有表达出最合适的用法, 你说的这段代码改成这样再看看, 同样可以运行, 原来的写法是个bug: List<Persistent<? extends Contact>> contacts = tob.querier.query(1, 1, Contact.class, ContactQ.OWNER$ID + " = ? AND " + ContactQ.NAME + " = ?", user.getID(), contactName); 哦,其实也不完全算bug,最初的想法是演示TOB的自动JOIN特性,但是放在这个上下文变成了误导. 假设User上还有个 int age; 实例成员变量, 那么可以这么查询: List<Persistent<? extends Contact>> contacts = tob.querier.query(1, -1, Contact.class, ContactQ.OWNER$AGE + " >= ? AND " + ContactQ.NAME + " LIKE ?", 22, "Robbin%"); 这样就找出所有 22 岁以上的用户的名字包含 Robbin 的联系人. 这里当指定了 ContactQ.OWNER$AGE 这个以后, TOB在下面自动生成相关 JOIN 的SQL, 当没有引用user上的属性时, 就不会JOIN, 不影响性能. 另外就是这样的查询, 如果User或者Contace有很多派生的子类, TOB也会在下面自动一一的去用同样的条件查询各个子类对应的关系数据库表, 返回的结果对象集合包含所有子类的符合条件的对象. 而这是直接就这样的, 不肖任何额外配置. |
|
返回顶楼 | |
发表时间:2006-11-13
complystill 写道 partech 写道 这能比么? 人家Object是Java语言类的根基。要用java就没法不用Object。 你不成也强制人家说"要持久化,就一定要用我提供的父类,别无二法"。 即使将来OO的数据库流行起来,我相信也不会象你现在给出的实现,仅仅需要剥离OR转化的部分就是了。 O的转化和映射是很自然和简单的, 关键的问题在R. 如果不是基于一定的固有模型, OO上出不来R的形式的, 这也是现有OODB都没有解决的问题. 要用面向对象的持久, 就没法不用一个持久的Relation基类. 如果是OO数据库,为啥还要转化,还要出来R的形式? complystill 写道 BookImpl 是应用程序自己写么? setPages(int); 里的逻辑没怎么看懂? 是业务逻辑还是持久逻辑? 另外没有见到Book和Writer互取的写法, 从一个Book获得Writer, 或者反过来要怎么搞的? 还有查询怎么支持的? BookImpl不需要自己写,模型驱动的。EMF的目的,实际上是三合一,UML/XML/Java。 如果你关心上面片断的细节,可以看这里: http://dev.eclipse.org/viewcvs/indextools.cgi/*checkout*/org.eclipse.emf/doc/org.eclipse.emf.doc/references/overview/EMF.html |
|
返回顶楼 | |
发表时间:2006-11-14
partech 写道 如果是OO数据库,为啥还要转化,还要出来R的形式? 如果不需要R, 那为什么到现在还是离不开关系数据库? 建模OO的R是脱离关系数据库, 同时还能实现相等能力的根本解决之道. partech 写道 complystill 写道 BookImpl 是应用程序自己写么? setPages(int); 里的逻辑没怎么看懂? 是业务逻辑还是持久逻辑? 另外没有见到Book和Writer互取的写法, 从一个Book获得Writer, 或者反过来要怎么搞的? 还有查询怎么支持的? BookImpl不需要自己写,模型驱动的。EMF的目的,实际上是三合一,UML/XML/Java。 如果你关心上面片断的细节,可以看这里: http://dev.eclipse.org/viewcvs/indextools.cgi/*checkout*/org.eclipse.emf/doc/org.eclipse.emf.doc/references/overview/EMF.html 在有空仔细研究一番之前, 有关原理性的东西想在这里先讨论一下. 如果Book是用UML画出来,自动生成的,而BookImpl又不能自己实现,那么特定的一些比较复杂的自身逻辑怎么融入到Book这个最终能够运行的类里去呢? UML应该还没有伪代码语法可以编译成程序语言吧? 如果说要再写一个包装类, 那好像有点违背OO原则(虽然也可以说是代理模式, 但这个代理只是为了插入本来就属于它自己的逻辑). 或者说要从BookImpl派生应用自己的类, 那不是比你反对的从TOB公共基类派生更够呛? 好歹TOB的应用持久类是应用自己的继承树; 如果应用要从模型生成的类去派生, 那么对于一个有子类的模型类, 你怎么样在应用里实现它的公共逻辑给子类用?? 目前的数据库管理系统(包括关系数据库在内), 其实基于B+树及其衍生算法实现的查询优化能力是非常重要的资产之一. 而实体关系模型是在以磁盘为主体存储介质的方案下与这种索引访问法(ISAM)的最优结合. 我觉得XML确实是好东西, 不过用在持久存储方面, 要形成完善成熟的检索优化技术还有很长的路要走. 另外就是循环引用方面, XML天生是树状模型, 虽然可以通过id来加上引用能力,但是要描述网络的持久拓扑结构还是不太自然, 甚至很困难. 所以我很想看一个简单的例子或者说明, 比如下面这两个关系: 婚姻关系(二元关系)和亲子关系(三元关系), 用EMF怎么样从模型设计到可以产生执行代码. TOB的这些类可以直接执行, 你一旦得到一个Person实例, 他的配偶, 孩子集合都直接可得, 甚至可以直接得到儿子集合和女儿集合(这里的判断只是子女的性别,但用来证明可以用自定义条件过滤TOB维护的相关对象集合). 而你需要做的就只是写这些代码. Person类: @MakeSwappable public class Person extends TheObject { @Kin(iAm = "child") protected Father father; @Kin(iAm = "child") protected Mother mother; @Kin(iAm = { "father", "mother" }, theyAre = "child") protected final Set<Child> children = new TreeSet<Child>( new ChildComparator()); @Kin(iAm = { "father", "mother" }) protected final Set<Child> sons = new TreeSet<Child>(new ChildComparator()) { private static final long serialVersionUID = 1L; public boolean add(Child c) { if (c.o.gender != Gender.MALE) return false; return super.add(c); } }; @Kin(iAm = { "father", "mother" }) protected final Set<Child> daughters = new TreeSet<Child>( new ChildComparator()) { private static final long serialVersionUID = 1L; public boolean add(Child c) { if (c.o.gender != Gender.FEMALE) return false; return super.add(c); } }; @Kin(iAm = { "husband", "wife" }, thisIs = { "wife", "husband" }) protected Spouse spouse; public Person() { birthday = new Date(); name = new Name(); } public Spouse getSpouse() { return spouse; } public Father getFather() { return father; } public Mother getMother() { return mother; } public Set<Child> getChildren() { return children; } public Set<Child> getSons() { return sons; } public Set<Child> getDaughters() { return daughters; } private static class ChildComparator implements Comparator<Child> { public int compare(Child c1, Child c2) { return (int) (c2.o.birthday.getTime() - c1.o.birthday.getTime()); } } } Marriage类: @MakeSwappable public class Marriage extends TheRelation { abstract public class Spouse extends Role<Person> { protected Spouse(Persistent<? extends Person> person) { super(person); } } public class Husband extends Spouse { protected Husband(Persistent<? extends Person> man) { super(man); } } public class Wife extends Spouse { protected Wife(Persistent<? extends Person> woman) { super(woman); } } @Tie protected Husband husband; @Tie protected Wife wife; public Marriage(Persistent<Person> man, Persistent<Person> woman) { assert man != null : "Who is marrying noman?"; assert woman != null : "Who is marrying nowoman?"; this.husband = new Husband(man); this.wife = new Wife(woman); } protected Marriage() { } @Retying( { "husband", "wife" }) public void newPair(Persistent<Person> husband, Persistent<Person> wife) { this.husband = new Husband(husband); this.wife = new Wife(wife); } public Husband getHusband() { return husband; } public Wife getWife() { return wife; } } Parentage类: @MakeSwappable public class Parentage extends TheRelation { public class Father extends Role<Person> { protected Father(Persistent<? extends Person> p) { super(p); } } public class Mother extends Role<Person> { protected Mother(Persistent<? extends Person> p) { super(p); } } public class Child extends Role<Person> { protected Child(Persistent<? extends Person> p) { super(p); } } @Tie protected Father father; @Tie protected Mother mother; @Tie protected Child child; public Parentage(Persistent<Person> father, Persistent<Person> mother, Persistent<Person> child) { assert father != null : "Who can make children without a father?"; assert mother != null : "Who can make children without a mother?"; assert child != null : "No child, no parent!"; this.father = new Father(father); this.mother = new Mother(mother); this.child = new Child(child); } protected Parentage() { } @Retying( { "father", "mother" }) public void adoptBy(Persistent<Person> newFather, Persistent<Person> newMother) { this.father = new Father(newFather); this.mother = new Mother(newMother); } @Retying("child") public void changeChild(Persistent<Person> child) { this.child = new Child(child); } public Child getChild() { return child; } public Mother getMother() { return mother; } public Father getFather() { return father; } } |
|
返回顶楼 | |