对双向相关bean的更多思考
来源:互联网 发布:淘宝宝贝详情页图片 编辑:程序博客网 时间:2024/05/17 17:41
- 对双向相关bean的更多思考
对双向相关bean的更多思考
上次我们讨论了如何用双向相关bean实现一对多关系,今天我们来讨论另一种重要的关系,即多对多关系。为了能更好的说明这种关系,我们用作者(Writer)和书(Book)的关系来说明。
- 以下代码描述了一个图书类(Book)和一个作者类(Writer)以及它们共同继承的基类(PojoSupport),图书和作者关系为“一本书可能由多个作者创作,一位作者可能写了多本书,为此我们还需要一个体现作者和图书关系的BookWriter类。”
public class Book extends PojoSupport<Book> { public int id; public java.lang.String title; public java.util.Collection<BookWriter> bookWriter; public java.util.Collection<BookWriter> getBookWriter() { if (bookWriter == null) bookWriter = new java.util.LinkedHashSet<BookWriter>(); return bookWriter; } public java.util.Iterator<BookWriter> getIteratorBookWriter() { if (bookWriter == null) bookWriter = new java.util.LinkedHashSet<BookWriter>(); return bookWriter.iterator(); } public void setBookWriter(java.util.Collection<BookWriter> newBookWriter) { removeAllBookWriter(); for (java.util.Iterator<BookWriter> iter = newBookWriter.iterator(); iter .hasNext();) addBookWriter((BookWriter) iter.next()); } public void addBookWriter(BookWriter newBookWriter) { if (newBookWriter == null) return; if (this.bookWriter == null) this.bookWriter = new java.util.LinkedHashSet<BookWriter>(); if (!this.bookWriter.contains(newBookWriter)) { this.bookWriter.add(newBookWriter); newBookWriter.setBook(this); } } public void removeBookWriter(BookWriter oldBookWriter) { if (oldBookWriter == null) return; if (this.bookWriter != null) if (this.bookWriter.contains(oldBookWriter)) { this.bookWriter.remove(oldBookWriter); oldBookWriter.setBook((Book) null); } } public void removeAllBookWriter() { if (bookWriter != null) { BookWriter oldBookWriter; for (java.util.Iterator<BookWriter> iter = getIteratorBookWriter(); iter .hasNext();) { oldBookWriter = (BookWriter) iter.next(); iter.remove(); oldBookWriter.setBook((Book) null); } } } @Override public int getId() { return id; } @Override public void setId(int id) { this.id = id; } public java.lang.String getTitle() { return title; } public void setTitle(java.lang.String title) { this.title = title; }}
public class Writer extends PojoSupport<Writer> { public int id; public java.lang.String name; public java.util.Collection<BookWriter> bookWriter; public java.util.Collection<BookWriter> getBookWriter() { if (bookWriter == null) bookWriter = new java.util.LinkedHashSet<BookWriter>(); return bookWriter; } public java.util.Iterator<BookWriter> getIteratorBookWriter() { if (bookWriter == null) bookWriter = new java.util.LinkedHashSet<BookWriter>(); return bookWriter.iterator(); } public void setBookWriter(java.util.Collection<BookWriter> newBookWriter) { removeAllBookWriter(); for (java.util.Iterator<BookWriter> iter = newBookWriter.iterator(); iter .hasNext();) addBookWriter((BookWriter) iter.next()); } public void addBookWriter(BookWriter newBookWriter) { if (newBookWriter == null) return; if (this.bookWriter == null) this.bookWriter = new java.util.LinkedHashSet<BookWriter>(); if (!this.bookWriter.contains(newBookWriter)) { this.bookWriter.add(newBookWriter); newBookWriter.setWriter(this); } } public void removeBookWriter(BookWriter oldBookWriter) { if (oldBookWriter == null) return; if (this.bookWriter != null) if (this.bookWriter.contains(oldBookWriter)) { this.bookWriter.remove(oldBookWriter); oldBookWriter.setWriter((Writer) null); } } public void removeAllBookWriter() { if (bookWriter != null) { BookWriter oldBookWriter; for (java.util.Iterator<BookWriter> iter = getIteratorBookWriter(); iter .hasNext();) { oldBookWriter = (BookWriter) iter.next(); iter.remove(); oldBookWriter.setWriter((Writer) null); } } } @Override public int getId() { return id; } @Override public void setId(int id) { this.id = id; } public java.lang.String getName() { return name; } public void setName(java.lang.String name) { this.name = name; }}
辅助类PojoSupport的用处是提供一些辅助方法,使得从数据库中加载的对象可以像java本地对象一样具有等价替换的功能
public abstract class PojoSupport<T extends PojoSupport<T>> { public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PojoSupport<?> other = (PojoSupport<?>) obj; if (getId() == null) { if (other.getId() != null) return false; } else if (!getId().equals(other.getId())) return false; return true; }}
以及一个专门用于描述Book和Writer关系的关系类BookWriter。我们约定,对于专门用于描述多对多关系的类,采用两个类名连写的方式命名(因此在此处命名BookWriter或者WriterBook都是可以的)。
public class BookWriter extends PojoSupport<BookWriter> { public int id; public Book book; public Writer writer; public Book getBook() { return book; } public void setBook(Book newBook) { if (this.book == null || !this.book.equals(newBook)) { if (this.book != null) { Book oldBook = this.book; this.book = null; oldBook.removeBookWriter(this); } if (newBook != null) { this.book = newBook; this.book.addBookWriter(this); } } } public Writer getWriter() { return writer; } public void setWriter(Writer newWriter) { if (this.writer == null || !this.writer.equals(newWriter)) { if (this.writer != null) { Writer oldWriter = this.writer; this.writer = null; oldWriter.removeBookWriter(this); } if (newWriter != null) { this.writer = newWriter; this.writer.addBookWriter(this); } } } @Override public int getId() { return id; } @Override public void setId(int id) { this.id = id; }}
细心的读者可以已经看出来了,多对多关系其实就是两个一对多关系,只不过这两个“一”是同一个类。那我们写了这么多代码之后,这个模型的质量到底如何呢?我们使用以下代码来描述这样一个场景:
作者张三(w1)写了两本书,名为《3的故事》(b3)和《7的传奇》(b7),作者李四(w2)也写了两本书,名为《4的诗歌》(b4)和《7的传奇》(b7),其中《7的传奇》(b7)为张三李四合著。
Writer w1 = new Writer(); w1.setId(1); w1.setName("张三"); Writer w2 = new Writer(); w2.setId(2); w2.setName("李四"); Book b3 = new Book(); b3.setId(3); b3.setTitle("3的故事"); Book b4 = new Book(); b4.setId(4); b4.setTitle("4的诗歌"); Book b7 = new Book(); b7.setId(7); b7.setTitle("7的传奇"); BookWriter bw31 = new BookWriter(); bw31.setId(31); bw31.setBook(b3); bw31.setWriter(w1); BookWriter bw42 = new BookWriter(); bw42.setId(42); bw42.setBook(b4); bw42.setWriter(w2); BookWriter bw71 = new BookWriter(); bw71.setId(71); bw71.setBook(b7); bw71.setWriter(w1); BookWriter bw72 = new BookWriter(); bw72.setId(72); bw72.setBook(b7); bw72.setWriter(w2); w1.addBookWriter(bw31); w1.addBookWriter(bw71); w2.addBookWriter(bw42); w2.addBookWriter(bw72);
我们会发现,把以上模型中w1、w2、b3、b4、b7任何一个序列化后,得到的信息量都是完全相同的。(具体原因可见我的前一篇博文《对于双向相关bean的一些思考》>http://blog.csdn.net/ro4074/article/details/43966013)
以把w1序列化为例,我们把它序列化后会发现:
w1.name = "张三"; w1.bookWriter[0].book.title = "3的故事"; w1.bookWriter[1].book.title = "7的传奇"; w1.bookWriter[1].book.bookWriter[0].writer.name = "张三"; w1.bookWriter[1].book.bookWriter[1].writer.name = "李四"; w1.bookWriter[1].book.bookWriter[1].writer.bookWriter[0].book.title = "4的诗歌"; w1.bookWriter[1].book.bookWriter[1].writer.bookWriter[1].book.title = "7的传奇";
由此可见我们的模型还是很可靠的,就是调用的时候有些繁琐。但是在实际开发网络应用时,如果使用mybatis或其他orm工具,可以很轻易地做到这一点。比如一句像下面这样的代码:
writerService.loadBook(writer, bookWriterCondition);
就可以把指定writer的所有bookWriter全都装载进来,而这些bookWriter中又都包含了相应的book。
以上我们用代码诠释了多对多这一逻辑关系,看起来已经没有任何问题能难住我们了…………且慢,真实世界从来都是残酷的(对程序员来说尤甚),我们遇到的绝大部分对象关系都不是单纯的一对多或者多对多,而是两者的结合。比如:
还是writer和book间的关系,现在每本书都有且只有一个主要作者(mainWriter)和一些合著者(coWriter),同时这些书的英文版又需要高水平的译者,这些译者同样也是作家,所以我们假定每本书还需要一个唯一的主要译者(mainTranslator)和一些合作译者(coTranslator),这里面的mainWriter、coWriter、mainTranslator、coTranslator都属于Writer类,那要如何用双向相关bean实现Book和Writer的关系呢,这就放到下一篇博文《对双向相关bean的最终思考》来说吧。
- 对双向相关bean的更多思考
- 对双向相关bean的一些思考
- 对JPA实体关系管理双向关联的一些思考
- 对思考的思考
- 对操作系统开发相关的一些问题的思考
- 成功--留给我们更多的是"思考".
- 对windows更多的理解
- 对无效思考的思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- 关于XAML,C#和WPF的更多思考的更多思考
- mfcs100ud.lib(dllmodul.obj) : error LNK2005: _DllMain@12 已经在 dllmain.obj 中定义
- 扩展欧几里得,逆元初识(poj 1061+codeforce 7C line+hdu 1576 A/B)
- 关于C语言中的局部变量和全局变量的分析
- LeetCode 101:Binary Tree Level Order Traversal
- Sublime Text 3 快捷键
- 对双向相关bean的更多思考
- jodd.bean.BeanException: Simple property not found错误
- dmytrodanylyk/circular-progress-button源码解析(二)
- 由一题讨论C语言中的“指针数组作main函数的形参”即 main(int argc,char *argv[])的使用
- android 访问网络三 (基于httpclient)
- 嵌入式软件开发培训笔记——s5pc100裸机编程预备知识
- linux shell数据重定向(输入重定向与输出重定向)详细分析
- VMware下linux桥接模式联网配置和mysql的安装
- 嵌入式软件开发培训笔记——ARM体系结构、A8处理器内核及汇编指令集