java的几种对象(PO,VO,DAO,BO,POJO,DTO)解释

一、PO:persistant object 持久对象,可以看成是与数据库中的表相映射的java对象。最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合。PO中应该不包含任何对数据库的操作。 
二、VO:value object值对象。通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要.个人觉得同DTO(数据传输对象),在web上传递。

三、DAO:data access object 数据访问对象,是一个sun的一个标准j2ee设计模式 .此对象用于访问数据库。通常和PO结合使用,DAO中包含了各种数据库的操作方法。通过它的方法,结合PO对数据库进行相关的操作。夹在业务逻辑与数据 库资源中间。配合VO, 
提供数据库的CRUD操作...

四、BO(business object) 业务对象
从业务模型的角度看,见UML元件领域模型中的领域对象。封装业务逻辑的java对象,通过调用DAO方法,结合PO,VO进行业务操作。这个对象可以包括一个或多个其它的对象。 
比如一个简历,有教育经历、工作经历、 关系等等。 
我们可以把教育经历对应一个PO,工作经历对应一个PO, 关系对应一个PO。 
建立一个对应简历的BO对象处理简历,每个BO包含这些PO。 
这样处理业务逻辑时,我们就可以针对BO去处理。

(关于BO主要有三种概念 :
1 、只包含业务对象的属性; 
2 、只包含业务方法; 
3 、两者都包含。 
在实际使用中,认为哪一种概念正确并不重要,关键是实际应用中适合自己项目的需要)

五、POJO:plain ordinary java object 简单无规则java对象,我个人觉得它和其他不是一个层面上的东西,VO和PO应该都属于它。

六、DTO:Data Transfer Object(数据传输对象)DTO 是一组需要跨进程或网络边界传输的聚合数据的简单容器。它不应该包含业务逻辑,并将其行为限制为诸如内部一致性检查和基本验证之类的活动。注意,不要因实 现这些方法而导致 DTO 依赖于任何新类。在设计数据传输对象时,您有两种主要选择:使用一般集合;或使用显式的 getter 和 setter 方法创建自定义对象。(资料:http://baike.baidu.com/view/160599.htm)

O/R Mapping 是 Object Relational Mapping(对象关系映射)的缩写。通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据。在O/R Mapping的世界里,有两个基本的也是重要的东东需要了解,即VO,PO。 
  VO,值对象(Value Object),PO,持久对象(Persisent Object),它们是由一组属性和属性的get和set方法组成。从结构上看,它们并没有什么不同的地方。但从其意义和本质上来看是完全不同的。

1.VO是用new关键字创建,由GC回收的。 
  PO则是向数据库中添加新数据时创建,删除数据库中数据时削除的。并且它只能存活在一个数据库连接中,断开连接即被销毁。 
2.VO是值对象,精确点讲它是业务对象,是存活在业务层的,是业务逻辑使用的,它存活的目的就是为数据提供一个生存的地方。 
  PO则是有状态的,每个属性代表其当前的状态。它是物理数据的对象表示。使用它,可以使我们的程序与物理数据解耦,并且可以简化对象数据与物理数据之间的转换。 
3.VO的属性是根据当前业务的不同而不同的,也就是说,它的每一个属性都一一对应当前业务逻辑所需要的数据的名称。 
  PO的属性是跟数据库表的字段一一对应的。PO对象需要实现序列化接口。

PO:
persistant object持久对象
最形象的理解就是一个PO就是数据库中的一条记录。
好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。

BO:
business object业务对象
主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。
比如一个简历,有教育经历、工作经历、  关系等等。
我们可以把教育经历对应一个PO,工作经历对应一个PO,  关系对应一个PO。
建立一个对应简历的BO对象处理简历,每个BO包含这些PO。
这样处理业务逻辑时,我们就可以针对BO去处理。

VO :
value object值对象
ViewObject表现层对象
主要对应界面显示的数据对象。对于一个WEB页面,或者SWT、SWING的一个界面,用一个VO对象对应整个界面的值。

DTO :
Data Transfer Object数据传输对象
主要用于远程调用等需要大量传输对象的地方。
比如我们一张表有100个字段,那么对应的PO就有100个属性。
但是我们界面上只要显示10个字段,
客户端用WEB service来获取数据,没有必要把整个PO对象传递到客户端,
这时我们就可以用只有这10个属性的DTO来传递结果到客户端,这样也不会暴露服务端表结构.到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO

POJO :
plain ordinary java object 简单java对象
个人感觉POJO是最常见最多变的对象,是一个中间对象,也是我们最常打交道的对象。
一个POJO持久化以后就是PO
直接用它传递、传递过程中就是DTO
直接用来对应表示层就是VO

====================================================================

PO(persistant object)持久对象 
在o/r映射的时候出现的概念,如果没有o/r映射,就没有这个概念存在了.通常对应数据模型(数据库),本身还有部分业务逻辑的处理.可以看成是与数据库中的表相映射的java对象.最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合,只能存活在一个数据库连接中,断开连接即被销毁。  
O/R映射:层是持久层的一个特例,它的数据模型是对象模型(Object),存储模型是关系模型(Relational),cmp和Hibernate是对象模型到关系模型之间转换的两种不同实现。 
  
VO(value object)值对象 
精确点讲它是业务对象,是存活在业务层的,是业务逻辑使用的,它存活的目的就是为数据提供一个生存的地方。  
BO(business object)业务对象 
从业务模型的角度看,见UML元件领域模型中的领域对象。封装业务逻辑的java对象,通过调用DAO方法,结合PO,VO进行业务操作。 主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。比如一个简历,有教育经历、工作经历、社会关系等等。 我们可以把教育经历对应一个PO,工作经历对应一个PO,社会关系对应一个PO。 建立一个对应简历的BO对象处理简历,每个BO包含这些PO。 这样处理业务逻辑时,我们就可以针对BO去处理。  
  
POJO(plain ordinary java object)简单无规则java对象 
纯的传统意义的java对象.就是说在一些Object/Relation Mapping工具中,能够做到维护数据库表记录的persisent object完全是一个符合Java Bean规范的纯Java对象,没有增加别的属性和方法.我的理解就是最基本的Java Bean,只有属性字段及setter和getter方法!. 
DAO(data access object)数据访问对象 
是sun的一个标准j2ee设计模式,这个模式中有个接口就是DAO,它负责持久层的操作.为业务层提供接口.此对象用于访问数据库.通常和PO结合使用,DAO中包含了各种数据库的操作方法.通过它的方法,结合PO对数据库进行相关的操作.夹在业务逻辑与数据库资源中间.配合VO,提供数据库的CRUD操作。 
DTO (Data Transfer Object)数据传输对象 
主要用于远程调用等需要大量传输对象的地方。 
比如我们一张表有100个字段,那么对应的PO就有100个属性。 
但是我们界面上只要显示10个字段, 
客户端用WEB service来获取数据,没有必要把整个PO对象传递到客户端, 
这时我们就可以用只有这10个属性的DTO来传递结果到客户端,这样也不会暴露服务端表结构.到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO。 
TO(Transfer Object),数据传输对象  
在应用程序不同tie(关系)之间传输的对象 


 

j2ee中,经常提到几种对象(object),理解他们的含义有助于我们更好的理解面向对象的设计思维。 
    POJO(plain old java object):普通的java对象,有别于特殊的java对象(含继承约束等)和EJB。POJO一般只有一系列的属性和相应的get、set方法。 
    PO(persistant object):持久化对象,有别于POJO,必须对应数据库中的实体。一个PO对应数据库的一条记录。持久化对象的生命周期与数据库密切相关,只能存在于connection之中,连接关闭后,PO就消失了。 
    PO相对于POJO有诸多不同,比如PO中会有保存数据库entity状态的属性和方法。但是ORM(object-relation mapping)追求的目标是PO和POJO的一致,所以在程序员的日常开发中,都是将POJO作为PO使用,而将POJO转化为PO的功能交给hibernate等框架来实现。 
    DTO(data transfer object):数据传输对象,以前被称为值对象(VO,value object),作用仅在于在应用程序的各个子系统间传输数据,在表现层展示。与POJO对应一个数据库实体不同,DTO并不对应一个实体,可能仅存储实体的部分属性或加入符合传输需求的其他的属性。 
    DAO(data access object):数据访问对象。提供访问数据库的抽象接口,或者持久化机制,而不暴露数据库的内部详细信息。DAO提供从程序调用到持久层的匹配。 
    BO(business object):业务对象。主要是将业务逻辑封装为一个对象,该对象可以包含一个或多个其他对象。如,"Principal"(委托人),有"Name","Age"等属性,同时和"Employee"(雇员)有1对多的关系,这个"Principal"就可以作为一个与业务相关的PO。


 

DTO – 服务实现中的核心数据

在一个Web服务的实现中,我们常常需要访问数据库,并将从数据库中所取得的数据显示在用户页面中。这样做的一个问题是:用于在用户页面上展示的数据和从数据库中取得的数据常常具有较大区别。在这种情况下,我们常常需要向服务端发送多个请求才能将用于在页面中展示的数据凑齐。

  一个解决该问题的方法就是根据不同需求使用不同的数据表现形式。在一个服务实现中较为常见的数据表现形式有MO(Model Object,在有些上下文中也被称为VO,Value Object)和DTO(Data Transfer Object)。MO用来表示从数据库中读取的数据,而DTO则用来表示在网络上所传输的数据。

  在本文中,我们将讨论如何在一个Web服务的实现中使用DTO及MO,并会对其它一些相关数据表现形式,如View Model等进行简单地介绍。

 

Why DTO?

  无论是桌面应用还是Web服务,其内部的数据表现都是非常重要的。在一个初学者了解一个系统的时候,其首先需要了解整个系统中的各个组件的作用,然后再了解系统中的Workflow,即在执行业务逻辑时各个组件是如何协同工作的。在了解了这两部分之后,该初学者需要做的事情就是详细地梳理一遍数据是如何在整个系统中流动的,即是整理并理解数据流(Dataflow)的过程。而在真正理解了数据流后,该初学者才具有了在系统中开发的能力。

  整理数据流的过程是一个逐步细化的过程:从鉴别数据结构到该数据结构中的每个属性到底是如何使用的。在整个数据流中,任何一个属性值的改变都可能会导致数据的处理方式发生变化。

  在整理数据流的时候我们要做什么样的事情呢?首先我们需要鉴别出到底哪些数据会在各个组件之间进行传送,在传送过程中进行了什么样的转化,这些数据是如何构建出来的,又由它构建了哪些数据,最终这些数据是否被持久化到了本地存储中等等。

  而在整理数据流的过程中,数据的转化常常是最难理解的部分。一个数据类型的定义常常与其运行环境有关。例如在一个电子商务网站中,一个表示商品的类Product可能包含了该商品的所有信息:商品的名称,品牌,详细介绍,价格等。在用户使用电脑浏览器浏览的时候,这些信息都将被显示在页面上。但是在用户使用手机进行浏览时,我们就需要考虑如何为这些手机用户节省流量的问题。一种节省用户手机流量的方法就是首先显示商品的简略信息,并在用户决定查看商品的详细介绍时再从服务端下载商品的详细信息。在这种情况下,包含商品所有信息的类Product将不再是适合传输的数据结构。

  而问题不仅仅出在需要将数据结构拆分的情况下,更可能出现在数据合并的情况中。例如网页的UE为了提高用户体验,要求在产品页面中直接将该商品品牌的详细信息显示在页面中。在这种情况下,我们就需要在表示商品的类Product中添加一个记录该商品品牌的域brand。但是在数据库中,表示商品的类Product可能仅仅记录了商品品牌的ID。因此在业务逻辑中,我们就需要将Product和其对应的Brand合并在一起。

  甚至说,我们可以将事情弄得更复杂一些:

  在上面的图中,我们展示了数据在一个系统中可能存在的多种不同表现形式。在图片的中央位置的是一个服务器,多种客户端都将从它那里获得产品信息。就像前面所说,为了节省客户端的流量,服务端向移动客户端所发送的数据将是产品信息在服务端中的简略版本。而在一个浏览器访问该产品的时候,表示商品品牌的信息将内嵌在产品信息之中,以提供更好的用户体验。除了与客户端通讯,服务端之间也可能产生信息的交换。在该交换过程中,表示产品的Product以及表示品牌的Brand则彼此独立地在服务端之间传递。而就一个运行在远端的Agent而言,其可能仅仅需要一个Product的ID来监控产品在生产制作方面的状态。

  而这一切数据都应当从系统的数据库中得到。数据库中的数据不可能同时存储并维护这一系列数据结构,因此在一个复杂的系统中,数据库中的数据表示与系统中所传输的数据之间常常是不同的数据结构。常见的情况则是将其分为两类:一类用来访问数据库,在系统中表现数据库中所记录的数据,叫MO,即Model Object;另一类用来在网络中传输,叫DTO,即Data Transfer Object。

 

服务中的DTOMO

  在了解了我们为什么需要DTO和MO等数据的不同表示之后,就让我们来看看这些数据表示在一个Web服务中是如何工作的。

  先让我们从最简单的Web服务分层开始说起。一个最简单的Web服务主要分为数据访问层(DAL),业务逻辑层以及表现层三个部分。其中表现层是运行在客户端的,而其它两个层次则运行在服务端。当数据从DAL层读取出来的时候,其所记录的数据与数据库中所记录的数据是一致的,因此它们就是我们这篇文章中讨论的MO。而在传输给客户端的时候,这些数据可能会和MO不同,因此其为DTO:

  现在就让我们放大一下数据访问层,来看看数据访问层中MO所在的位置:

  首先要强调的是,实现数据访问层的方式有很多种,而上图所展示的仅仅是一种基于Repository模式的实现。通过Repository来实现DAL是一种最为常见的数据访问层实现方式。就像上图所展示的那样,在一个基于Repository模式的实现中,数据访问层将拥有一系列Repository实例。这些Repository实例依赖于系统所使用的ORM来将数据库中的数据转化为Java类实例。这些Java类实例实际上就是在该数据访问层所提供给业务逻辑层的MO。

  而DTO则用于在服务与客户之间以及服务和服务之间进行数据的传递。在这些传递过程中,对DTO的需求可能是多种多样的:

  上面的图片展示了一段Product这种类型的DTO在服务端和客户端以及服务端之间进行交互的过程。在该流程中,所需要传递的DTO并不相同:在使用浏览器读取和保存有关Product的信息时,两者的数据表现形式可能会有一些细微的差别。而在保存完毕后,服务可能会将新的Product作为负载来向其它服务器发送请求,而此时所使用的Product的表示又可能与前两种略有差别。如果为这些细微的差别定义很多不同的DTO,那么系统对数据的管理可能会遇到一系列麻烦。例如在一个复杂的系统中,DTO可能会按照下面的方式在系统中流转:

  在上图中,我们展示了一个DTO在依次流转过多个服务的情况。如果在DTO依次传递的过程中使用了不同的DTO表示,那么一个服务所需要的DTO可能和另一个服务中所拥有的DTO并不匹配。这便是DTO反过来会影响到架构设计的一个最简单的例子,却也是DTO管理中最常见的问题,那就是DTO的表现形式过多。如果为所有的不同需求都创建一个DTO,那么一个概念所对应的DTO可能多达5,6种,非常难于管理。这种管理上的困难常常存在于如何指定某个服务所需要使用的DTO种类,以及在更改DTO时需要同时修改一系列DTO的情况中。

  为了防止DTO由于不同的需求而衍生出过多的种类,服务实现中常常允许DTO中的数据包含一些冗余。

 

逐步添加你的DTO

  那么我们该如何向系统中添加DTO呢?答案是,根据情况决定。在项目的一开始,数据库中所存储的数据与页面所需要显示的数据常常是一致的,因此在这种情况下,我们并不需要DTO的帮助。而在所需要的数据和数据库所记录的数据不再一样的时候,我们就需要考虑是否需要在项目中添加DTO了。这时软件开发人员就需要问自己:这种所需要的数据与数据库中的数据不一致的情况是否常常出现?如果答案是“是”,那么我们就需要开始着手准备添加对DTO的支持。

  在系统中添加DTO主要有以下几部分工作需要完成:

  1. 添加DTO类。
  2. 添加从MO到DTO的转化逻辑。
  3. 将原本对MO的使用转换为对DTO的使用。

  相信读者最先注意到的就是第三点。可以想象到的是,如果将整个系统的MO替换成DTO,那么它的影响面将会非常大,而且非常容易出错。因此在一个大型项目中,我们常常需要预先判断DTO的必要性,进而尽早地添加DTO。

  让我们回过头来看看第一个任务应该如何完成。在一个系统中,DTO常常用来传输数据,因此其自身往往不带有任何逻辑。这也便是这些DTO常常被定义成JavaBean的原因。以JavaBean的形式来定义DTO带来了一个巨大的好处,那就是很多第三方类库都提供了生成JavaBean的功能。在这种情况下,软件开发人员只需要通过一系列描述性语言来描述这些DTO即可。这其中最常用的便是JAXB。

  在使用JAXB时,软件开发人员只需要在.xsd文件中编写一系列描述性信息:

复制代码
1 <xsd:complexType name="Address">
2   <xsd:sequence>
3     <xsd:element name="name" type="xsd:string"/>
4     <xsd:element name="street" type="xsd:string"/>
5     <xsd:element name="city" type="xsd:string"/>
6     <xsd:element name="state" type="xsd:string"/>
7   </xsd:sequence>
8   <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
9 </xsd:complexType>
复制代码

  那么在JAXB运行完毕后,相应的Java类型就将被生成:

复制代码
 1 @XmlAccessorType(AccessType.FIELD)
 2 @XmlType(name = "Address", propOrder = {
 3     "name",
 4     "street",
 5     "city",
 6     "state"
 7 })
 8 public class Address {
 9     protected String name;
10     protected String street;
11     ……
12     @XmlAttribute
13     @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
14     protected String country;
15 
16     public String getName() {
17         return name;
18     }
19 
20     public void setName(String value) {
21         this.name = value;
22     }
23 
24     public String getStreet() {
25         return street;
26     }
27 
28     public void setStreet(String value) {
29         this.street = value;
30     }
31     ……
32     public String getCountry() {
33         if (country == null) {
34             return "US";
35         } else {
36             return country;
37         }
38     }
39 
40     public void setCountry(String value) {
41         this.country = value;
42     }
43 }
复制代码

  是不是很简单?在知道了如何创建一个DTO之后,我们就需要考虑如何将MO转化成为DTO。当然,这依然有第三方工具可以帮助我们完成这个事情。一个较为著名的工具就是Dozer。使用Dozer也很简单,在它的配置文件里面标明需要相互转换的两个类型即可:

1 <mapping> 
2     <class-a>com.ambergarden.egoods.mo.Address</class-a>
3     <class-b>com.ambergarden.edoods.dto.Address</class-b>
4 </mapping>

  在运行时,Dozer会使用反射来对这两个类型中的各个同名属性进行匹配并赋值。如果两个类型中拥有不同名的属性,那么软件开发人员可以显式地指定相互匹配的属性:

复制代码
1 <mapping> 
2     <class-a>com.ambergarden.egoods.mo.Address</class-a>
3     <class-b>com.ambergarden.edoods.dto.Address</class-b>   
4     <field>
5         <a>name</a>
6         <b>owner</b>
7     </field>
8 </mapping>
复制代码

  除此之外,Dozer还支持非常多的转换功能,在这里我们便不一一进行介绍了。

  在有这些工具的辅助下,为系统添加DTO已经变得简单多了。在对DTO的日常维护中,我们可能需要添加一些新的DTO,或者更改已有的DTO。在这种情况下,我们只需要更改对DTO进行描述的文件并更新Dozer的配置文件即可。当然,如果在Dozer中使用了自定义转换逻辑,那么软件开发人员还需要更新相应的转换逻辑。

 

贫血的DTO

  DTO中只包含数据,并没有包含任何行为。“这我知道”,或许你会说。

  但是千万不要大意。这常常会导致你陷入贫血模型的陷阱中。在服务端的业务逻辑实现以及客户端的页面逻辑中,我们有时需要指定对这些数据的操作逻辑。从面向对象设计的角度来说,某些逻辑实际上就应该定义在这些类型中。但是由于DTO本身没有定义这些逻辑,因此我们需要在这些类型之外定义它们,例如在一个Helper类中为这些类型定义一系列辅助函数。

  一个最简单的示例就是对数据有效性的检查。例如在一个Person类中,我们使用一个整型数据记录了该人物的年龄:

1 class Person {
2     private int age;
3     ……
4 }

  那么在业务逻辑中,我们就需要检查该域是否被设置为负数。由于DTO是使用工具自动生成的,因此这些检查逻辑无法放在该DTO类中。作为一种变通方式,我们需要写一个辅助类来完成该功能。但随着这种需求越来越多,对这些辅助功能的管理将越来越困难。此时你就将完全陷入到贫血模型的陷阱中。

  也就是说,DTO的主要职责是为了传输数据,但它并不擅长,甚至是不适合在业务逻辑中表示一个复杂概念。一个复杂概念常常与一些可重用的复杂逻辑关联,但这正是DTO所不能办到的。

  为了解决这个问题,我们可以在服务端添加一个业务逻辑表现,即BO(Business Object)。在这种情况下,MO将不会直接转化为DTO,而是转化为BO。在所有业务处理完毕并需要将数据发送给客户的时候,BO将转化为DTO以进行传输。

  而在客户端,我们同样可以引入一层新的更适合于页面逻辑的数据表现。这种数据表现被称为VM(ViewModel),即为了表观展示所定义的模型。有时候,有些类库提供了更为简单的方法,例如YUI和ExtJS所提供的Mixin功能。

  当然,在添加这些数据展现形式之前,软件开发人员需要仔细考量添加这些模型所需要的工作量和所带来效益之间的平衡。

 

DTO vs. DAO

  有些人看到这个标题时可能会一愣。是的,两者并没有任何可比性。但是如果一个人了解了DTO,并知道了DAO是Data Access Object的缩写,那么他可能会很自然地认为DAO与DTO类似,是用来表示从DAL所取得的用来表示数据库中数据的类型。

  可实际上,DAO则是一种组织数据库访问逻辑的一种标准模式。也就是说,与其对应的应该是Repository模式等一系列数据访问的常用方法。因此在本文的最后,我们需要着重强调DAO和MO并不是一个概念。而由于本文主要着重介绍数据,并且DAO本身也可以作为一篇独立的博客,因此在本文中将不再对其进行详细地介绍。


 


DAO层、Service层、Controller层和view层

DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,DAO层的数据源配置,以及有关数据库连接的参数都在Spring的配置文件中进行配置。   
  
Service层:Service层主要负责业务模块的逻辑应用设计。同样是首先设计接口,再设计其实现的类,接着再Spring的配置文件中配置其实现的关联。这样我们就可以在应用中调用Service接口来进行业务处理。Service层的业务实现,具体要调用到已定义的DAO层的接口,封装Service层的业务逻辑有利于通用的业务逻辑的独立性和重复利用性,程序显得非常简洁。   
  
Controller层:Controller层负责具体的业务模块流程的控制,在此层里面要调用Serice层的接口来控制业务流程,控制的配置也同样是在Spring的配置文件里面进行,针对具体的业务流程,会有不同的控制器,我们具体的设计过程中可以将流程进行抽象归纳,设计出可以重复利用的子单元流程模块,这样不仅使程序结构变得清晰,也大大减少了代码量。   
  
View层 此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示,   
  
DAO层,Service层这两个层次都可以单独开发,互相的耦合度很低,完全可以独立进行,这样的一种模式在开发大项目的过程中尤其有优势,Controller,View层因为耦合度比较高,因而要结合在一起开发,但是也可以看作一个整体独立于前两个层进行开发。这样,在层与层之前我们只需要知道接口的定义,调用接口即可完成所需要的逻辑单元应用,一切显得非常清晰简单。   
  
DAO设计的总体规划需要和设计的表,和实现类之间一一对应。   
  
DAO层所定义的接口里的方法都大同小异,这是由我们在DAO层对数据库访问的操作来决定的,对数据库的操作,我们基本要用到的就是新增,更新,删除,查询等方法。因而DAO层里面基本上都应该要涵盖这些方法对应的操作。除此之外,可以定义一些自定义的特殊的对数据库访问的方法。   
  
Service逻辑层设计   
  
Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。   
  
在DAO层定义的一些方法,在Service层并没有使用,那为什么还要在DAO层进行定义呢?这是由我们定义的需求逻辑所决定的。DAO层的操作 经过抽象后基本上都是通用的,因而我们在定义DAO层的时候可以将相关的方法定义完毕,这样的好处是在对Service进行扩展的时候不需要再对DAO层进行修改,提高了程序的可扩展性。  

术语解释:

VO( View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象。

BO( Business Object):业务对象。 由Service层输出的封装业务逻辑的对象。

DO( Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。 == PO  == Entity

DTO( Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。

AO( Application Object):应用对象。 在Web层与Service层之间抽象的复用对象模型,极为贴近展示层,复用度不高。

POJO( Plain Ordinary Java Object):在本手册中, POJO专指只有setter/getter/toString的简单类,包括DO/DTO/BO/VO等。

Query:数据查询对象,各层接收上层的查询请求。 注意超过2个参数的查询封装,禁止使用Map类来传输。

说实话,术语太抽象,不利于理解,看完其实没解决啥疑惑,我会尽量用大白话(人话)来做解释,争取让大家都能看明白

废话不多说,先来看张图,看完图估计大部分人就已经有了一个直观的感受了

 
 

图解:

面对这个图,让我们先从承上启下的DTO开始入手

DTO(Data Transfer Object)数据传输对象

这个传输通常指的前后端之间的传输

DTO是一个比较特殊的对象,他有两种存在形式:

在后端,他的存在形式是java对象,也就是在controller里面定义的那个东东,通常在后端不需要关心怎么从json转成java对象的,这个都是由一些成熟的框架帮你完成啦,比如spring框架

在前端,他的存在形式通常是js里面的对象(也可以简单理解成json),也就是通过ajax请求的那个数据体

这也是为什么把他画成横跨两层的原因

这里可能会遇到个问题,现在微服务盛行,服务和服务之间调用的传输对象能叫DTO吗?

我的理解是看情况

DTO本身的一个隐含的意义是要能够完整的表达一个业务模块的输出

如果服务和服务之间相对独立,那就可以叫DTO

如果服务和服务之间不独立,每个都不是一个完整的业务模块,拆开可能仅仅是因为计算复杂度或者性能的问题,那这就不能够叫做DTO,只能是BO

VO(Value Object)值对象

VO就是展示用的数据,不管展示方式是网页,还是客户端,还是APP,只要是这个东西是让人看到的,这就叫VO

VO主要的存在形式就是js里面的对象(也可以简单理解成json)

VO和DTO的区别

主要有两个区别

一个是字段不一样,VO根据需要会删减一些字段

另一个是值不一样,VO会根据需要对DTO中的值进行展示业务的解释

举个简单的例子

DTO可能是这样的

{"gender":"男","age":35}

对于业务一来说只需要性别,而且因为是一个古风聊天室,也不能直接展示男,因此经过业务解释业务一的VO是

{"gender":"公子"}

对于业务二来说只需要年龄,而且不需要精确的年龄,因此经过业务解释业务二的VO是

{"age":"30~39"}

PO(Persistant Object)持久对象

PO比较好理解

简单说PO就是数据库中的记录,一个PO的数据结构对应着库中表的结构,表中的一条记录就是一个PO对象

通常PO里面除了get,set之外没有别的方法

对于PO来说,数量是相对固定的,一定不会超过数据库表的数量

等同于Entity,这俩概念是一致的

BO(Business Object)业务对象

BO就是PO的组合

简单的例子比如说PO是一条交易记录,BO是一个人全部的交易记录集合对象

复杂点儿的例子PO1是交易记录,PO2是登录记录,PO3是商品浏览记录,PO4是添加购物车记录,PO5是搜索记录,BO是个人网站行为对象

BO是一个业务对象,一类业务就会对应一个BO,数量上没有限制,而且BO会有很多业务操作,也就是说除了get,set方法以外,BO会有很多针对自身数据进行计算的方法

为什么BO也画成横跨两层呢?原因是现在很多持久层框架自身就提供了数据组合的功能,因此BO有可能是在业务层由业务来拼装PO而成,也有可能是在数据库访问层由框架直接生成

很多情况下为了追求查询的效率,框架跳过PO直接生成BO的情况非常普遍,PO只是用来增删改使用

BO和DTO的区别

这两个的区别主要是就是字段的删减

BO对内,为了进行业务计算需要辅助数据,或者是一个业务有多个对外的接口,BO可能会含有很多接口对外所不需要的数据,因此DTO需要在BO的基础上,只要自己需要的数据,然后对外提供

在这个关系上,通常不会有数据内容的变化,内容变化要么在BO内部业务计算的时候完成,要么在解释VO的时候完成

OK,到这里这些关系基本就理清楚了

等等,DO是什么

DO呢,标题不是还有个DO么?

上面这些概念基本上已经涵盖了全部的流程,DO只是跟其中一个概念相同

但是跟哪个概念相同呢?

现在主要有两个版本

一个是阿里巴巴的开发手册中的定义

DO( Data Object)这个等同于上面的PO

另一个是在DDD(Domain-Driven Design)领域驱动设计中

DO(Domain Object)这个等同于上面的BO

最后,让我们再说说实际应用

这几个概念很完整,我们在用的时候是必须按这个来做吗?

当然不是的,系统和系统的复杂度不同,协作水平不同,完全没有必要教条主义,这些概念全上

上哪些概念,省哪些,我给一些实际建议

1,PO这个没法省,不管叫PO还是Entity,怎么着都得有

2,一些工具类的系统和一些业务不是很复杂的系统DTO是可以和BO合并成一个,当业务扩展的时候注意拆分就行

3,VO是可以第一个优化掉的,展示业务不复杂的可以压根儿不要,直接用DTO

4,这也是最重要的一条,概念是给人用的,多人协作的时候一定要保证大家的概念一致,赶紧把这篇文章转发给跟你协作的人吧

转自:https://zhuanlan.zhihu.com/p/102389552

posted @ 2018-10-09 15:11  CharyGao  阅读(604)  评论(0编辑  收藏  举报