`
atell
  • 浏览: 161643 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

[Playframework文档中文翻译]领域对象模型(domain object model)

阅读更多

(原文链接:http://play-framework.herokuapp.com/zh/model " ) 来自"Playframework中文小站 " )

领域对象模型(domain object model)

本章译者:@freewind

在Play程序中,模型(model)占据了核心地位。它是程序操作的信息的特定领域的表现方式。

Martin Fowler这样定义模型:

负责表达业务概念,业务状态信息以及业务规则。尽管保存业务状态的技术细节是有基础设施层实现的,但是反应业务情况的状态是有本层控制并且使用的。领域层是业务软件的核心。

Java中有一个常见的反模式:仅仅把模型当作一个个的简单的Java Bean,里面就只有一些字段和getter/setter,然后把业务逻辑代码放到一个Service层中,在Service层中处理模型对象。

Martin fowler之后把这种反模式称为 贫血模型 :

贫 血模型一个明显的特征是它仅仅是看上去和领域模型一样,都拥有对象、属性、对象间通过关系关联。但是当你观察模型所持有的业务逻辑时,你会发现,贫血模型 中除了一些getter和setter方法,几乎没有其他业务逻辑。这种情况事实上是由一些设计规则中(design rules)规定不要把业务逻辑放到“领域模型”中造成的,取而代之的是把所有的业务逻辑都封装到众多service中。这些service对象在“领域 对象”(领域层)之上形成一个service层,而把“领域对象”当做数据使用。

贫血模型从根本上就违背了面向对象设计将属性与操作融 合的思想。贫血模型就是我们纯粹的面向对象忠实者(比如我和Eric)从Smalltalk早期就极力反对的面向过程化设计的风格。更糟糕的是,很多人认 为贫血模型就是真正的面向对象,进而也就完全领悟不到面向对象设计的真谛。

(注:这里引用的Martin fowler的两段话的翻译,均来自http://www.turingbook.com/article/details/25)

实际上想在Java中实现非贫血的模型,有时候是一件很困难的事情(因为Java的语法限制)。Play是通过对类进行增强而实现的。

属性(Properties)模拟

如 果我们去看Play的示例程序,就会发现很多类都声明了public的变量。如果你是一个有经验的Java程序员,看到这一定会觉得不可思议。如果在 Java(以及其它面向对象语言)中,把字段声明为private并且提供访问器和修改器才是最佳实践。因为“封装”是面向对象中的一个重要观念。

Java没有真正的内置的属性定义系统。它使用了一个命名规范叫Java Bean: Java对象的一个属性,即是一对getXxx/setXxx方法。如果这个属性是只读的,那就只提供一个getter.

虽然这套系统可以工作,但写起来非常繁琐。每一个属性,你都需要先声明一个private的变量,再写两个方法。而且,大多数的getter和setter都是非常简单而且都一样:

private String name;
 
public String getName() {
    return name;
}
 
public void setName(String value) {
    name = value;
}


Play的Model系统则可以自动生成这种模式,让我们的代码看起来更干净一些。实际上所有的public变量都会变成属性。这里有个约定:一个类所有的 public , non-static , non-final 字段,都将被看作一个属性。

例如,当我们声明了一个类:

public class Product {


public String name; public Integer price; }

实际上被载入的类会变成这样:

public class Product {
 
    public String name;
    public Integer price;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Integer getPrice() {
        return price;
    }
 
    public void setPrice(Integer price) {
        this.price = price;
    }
}


当你想访问一个属性时,你可以直接写成:

product.name = "My product";
product.price = 58;


在载入时,它将被替换为:

product.setName("My product");
product.setPrice(58);


警告!

如果你依赖于Play的自动生成,你没有办法直接使用getter和setter来访问属性,因为这些方法是在运行时才生成的。所以,当你在代码中调用getter/setter,编译器会提醒你找不到该方法。

当然,你也可以自己定义getter和setter,此时play会使用你自己定义的方法。

所以,如果想来保护Product类的price属性,我们可以写成:

public class Product {
 
    public String name;
    public Integer price;
 
    public void setPrice(Integer price) {
        if (price < 0) {
            throw new IllegalArgumentException("Price can’t be negative!");
        }
        this.price = price;
    }
}


如果我们给它赋一个负值,将会抛出一个异常:

product.price = -10: // Oops! IllegalArgumentException


Play将总是使用已经存在的getter和setter。看以下代码:

@Entity
public class Data extends Model {
 
   @Required
   public String value;
   public Integer anotherValue;
 
   public Integer getAnotherValue() {
       if(anotherValue == null) {
           return 0;
       }
       return anotherValue;
   }
 
   public void setAnotherValue(Integer value) {
       if(value == null) {
           this.anotherValue = null;
       } else {
           this.anotherValue = value * 2;
       }
   }
 
   public String toString() {
       return value + " - " + anotherValue;
   }
 
}


从另一个类中进行判断:

Data data = new Data();
data.anotherValue = null;
assert data.anotherValue == 0;
data.anotherValue = 4
assert data.anotherValue == 8;


一切运行正常。因为增强的类遵守了Java Bean的约定,所以你在一个使用JavaBean规范的其它库里使用它,也没问题。

设置一个数据库来持久化你的模型对象

通常你都需要把模型对象中的数据持久化,最常用的方法就是使用数据库。

在开发阶段,我们可以快速启动一个嵌入式的内存数据库,或者一个文件数据库(在我们项目中的一个子目录中),把数据保存进去。我们可使用 配置数据库 来进行配置。

Play下载包中,已经包含了H2和MySQL数据库的JDBC驱动,位于 $PLAY_HOME/framework/lib/ 目录。如果你使用PostgreSQL或者Oracle,你必须把相应的JDBC驱动程序放进去,或者放到你的程序的 lib/ 目录中。

我们需要在conf/application.conf文件中,配置与数据库相关的连接信息,比如 db.url , db.driver , db.userdb.pass :

db.url=jdbc:mysql://localhost/test
db.driver=com.mysql.jdbc.Driver
db.user=root
db.pass=


我们还可以使用 jpa.dialect 来配置一个JPA方言(dialect).

在代码中,我们可以从 play.db.DB 中取得 java.sql.Connection 对象,然后按标准方式使用它。

Connection conn = DB.getConnection();
conn.createStatement().execute("select * from products");


使用Hibernate来持久化模型对象

我们可以使用Hibernate(通过JPA)来自动将Java对象持久化到数据库中。

当我们把@javax.persistence.Entity 注解加到某个Java对象上来定义JPA实体时,Play会自动开启JPA实体管理器。

@Entity
public class Product {
 
    public String name;
    public Integer price;
}


警告!

一个常见的错误是使用了Hibernate的@Entity 注解。我们应该使用JPA中的@Entity 才对,因为Play是通过JPA的API来使用Hibernate的。

然后我们可以通过 play.db.jpa.JPA 来取得一个EntityManager:

EntityManager em = JPA.em();
em.persist(product);
em.createQuery("from Product where price > 50").getResultList();


Play提供了一个非常好用的基类来处理JPA相关的操作。我们只需要继承 play.db.jpa.Model 即可。

@Entity
public class Product extends Model {
 
    public String name;
    public Integer price;
}


然后,我们就可以直接使用 Product 上的一些简单方法,来对它进行操作:

Product.find("price > ?", 50).fetch();
Product product = Product.findById(2L);
product.save();
product.delete();


支持多数据库

我们可以配置Play来使用多个(独立的)数据库。

conf/application.conf 中,以‘db.’开头的key是用来配置默认数据库的(比如 db.url )。如果想再配置一个其它的数据库,需要在‘db’后面增加一个下划线,和一个名称。如下:

db_other.url=jdbc:mysql://localhost/test
db_other.driver=com.mysql.jdbc.Driver
db_other.user=root
db_other.pass=


我们定义了一个名为‘other’的数据库。要对它进行其它的配置,则这样做:

db_other.jpa.dialect=<dialect>


我们可以在程序中,这样取得该数据库的连接:

Connection conn = DB.getDBConfig("other").getConnection()


DB.getDBConfig(configName) 返回一个含有与 play.db.DB 类中静态方法相同方法的对象。

保持模型为“无状态”(stateless)

Play设计成“完全无共享”的架构,以保证整个程序完全没有状态。这样做,可以让我们同时跑任意多个相同的程序,同时向外提供服务(集群)。

为了达到模型无状态,应该注意什么? 不要在Java heap中保存多个请求共享的模型对象

如果想在多个请求中共享数据,我们有多种选择:

  1. 如果数据很小很简单,直接把它保存在session或flash中。但要注意,每一个不能超过4KB,并且只能是String
  2. 把数据持久化(例如保存在数据库中)。例如,我们需要创建一个跨越多个请求的“wizard”对象:
    • 当第一个请求到达时,初始化该对象,并把它保存在数据库中
    • 把新创建的对象的ID值放到flash域
    • 当新请求到来时,从flash域中取出该ID,再到数据库中取出对应的数据,更新并重新保存
  3. 把数据保存在非持久化设备(如Cache)中。例如,还是创建那个跨越多个请求的“wizard”对象:
    • 当第一个请求到达时,初始化该对象,并把它保存在Cache中
    • 把新创建的对象的ID值放到flash域
    • 当新请求到来时,从flash域中取出该ID,再从Cache中取出对应的数据,更新并重新保存在cache中
    • 当所有相关请求结束时,将该对象持久化(比如保存在数据库中)

虽然Cache是一个不可靠的保存处,但你把一个对象保存进去后,通常能够再取出来。在某些情况下,Cache是一个可以用来替代Java Servlet session的好选择。

继续讨论

现在我们将讲解如果使用 JPA persistence 来持久化模型。

(原文链接:http://play-framework.herokuapp.com/zh/model " ) 来自"Playframework中文小站 " )

分享到:
评论

相关推荐

    playframework中文教程.zip

    这个“playframework中文教程.zip”压缩包很可能是为了帮助中文用户更好地理解和学习Play Framework而准备的资源。 Play Framework 的主要特点包括: 1. **轻量级**:与传统的Java EE规范相比,Play Framework ...

    play framework api,play! framework api,play api

    framework api,play api"都是指Play Framework的API文档,它包含了框架的所有公共类、方法和接口,供开发者在编写代码时查阅和引用。API文档是理解框架工作原理、学习如何使用框架功能以及解决问题的关键资源。 ...

    Play框架中文文档.pdf

    Play框架中文文档.pdf

    Play Framework Cookbook.pdf

    - **模型与数据库交互**:涵盖数据库配置、数据访问对象(DAO)模式、查询操作等内容。 - **视图层开发**:讲解 Mustache 模板引擎的使用方法,以及如何实现动态页面的渲染。 - **安全性与认证**:探讨应用安全...

    playframework框架项目部署文档

    Play Framework是一个强大的、基于Java和Scala的开源Web应用程序框架,它采用模型-视图-控制器(MVC)架构模式,以简洁的API和直观的开发体验受到开发者喜爱。本篇文章将详述如何在Windows环境下安装配置Play环境...

    Play framework框架

    Play Framework框架 Play Framework框架是一种基于Java的软件框架,旨在提高开发效率和提供REST式的架构风格。该框架可以让开发者继续使用他们喜欢的开发环境或繻库,不需要切换到另一种语言、IDE或者其他繻库。 ...

    PlayFramework框架验证.pdf

    PlayFramework提供了一套完整的验证机制,允许开发者通过声明式的方式定义模型(Model)或表单(Form)的验证规则,并在控制器(Controller)中进行校验。 PlayFramework的验证机制使用了play.data.validation包下...

    Play Framework2本教程

    Play Framework2是一个强大的Java和Scala应用开发框架,它以其简洁的API、快速的开发周期以及对Web标准的紧密集成而闻名。本教程旨在为初学者和有经验的开发者提供全面的指导,帮助他们掌握Play Framework2的核心...

    play framework 框架手册 word 版

    《Play Framework 框架手册》是一份深入介绍Play框架的文档,主要涵盖了从基础概念到高级特性的全面内容,适合初学者和经验丰富的开发者参考。以下是对手册中部分核心知识点的详细阐述: 1. **MVC应用程序模型**:...

    Play framework 2.0入门教程(三)的源代码,Play留言板

    1. **模型(Model)**:在Play中,模型通常由领域对象组成,这些对象代表应用程序中的实体。例如,可能会有一个`Message`类,它包含留言的内容、作者等属性。模型通常使用Ebean或Anorm等持久化库来与数据库交互。 2...

    playframework 框架学习之路 1

    Play Framework 是一个基于Java和Scala的开源Web应用框架,它遵循模型-视图-控制器(MVC)架构模式。在“Playframework框架学习之路 1”中,我们可能要探讨这个框架的基础概念、安装过程以及如何创建一个简单的应用...

    Play Framework Cookbook

    ### Play Framework Cookbook 知识点解析 #### 一、Play Framework 概览 - **定义与背景**:Play Framework 是一款基于 Java 和 Scala 的高性能、轻量级 Web 开发框架。它采用 RESTful 架构设计,支持热重载功能,...

    Play Framework应用程序框架 v2.7.9.zip

    Play Framework是一款基于Java和Scala的开源Web应用框架,它遵循模型-视图-控制器(MVC)架构模式,旨在提供高效、简洁且可测试的开发环境。标题中的"v2.7.9"指的是该框架的特定版本,通常每个新版本会包含性能优化...

    play,play framework资料大全

    这份文档通常会涵盖Play Framework的基本概念、安装步骤、项目结构、路由配置、模板引擎、控制器、模型、数据库集成、测试以及部署等核心内容。通过阅读这份文档,开发者可以全面了解Play Framework的各个方面,快速...

    playFramework1.2.3

    Play Framework是Java Web开发领域的一款流行开源框架,以其简洁、高效和模块化的特性著称。在标题"playFramework1.2.3"中,我们关注的是Play Framework的1.2.3版本。这个版本是在其早期发展的一个稳定版本,提供了...

    play framework db

    在Play Framework中,数据库操作是通过集成Java Persistence API (JPA) 实现的,这使得开发者能够方便地进行领域对象的持久化,而无需深入理解底层数据库的复杂细节。本文将详细探讨Play Framework如何使用JPA进行...

    Play framework 2.0 -第一个应用程序

    《Play Framework 2.0 - 创建你的第一个应用程序》 Play Framework 2.0 是一个开源的Web应用框架,它基于Scala和Java语言,遵循“模式-动作”(Action)架构,提供了一种轻量级、敏捷开发的方式。本篇文章将引导你...

    Play_Framework(手册、配置文档、标签等)

    2. **异步编程模型**:Play Framework 使用非阻塞I/O和事件驱动模型,使得它在处理高并发请求时表现优秀,特别适合构建实时Web应用。 3. **路由系统**:Play 的路由文件定义了URL到控制器方法的映射,提供了声明式...

    playframework javaweb

    playframework javaweb playframework javaweb

    Mastering Play Framework for Scala

    Mastering Play Framework for Scala

Global site tag (gtag.js) - Google Analytics