play框架使用起来(10)
Posted zyhlal
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了play框架使用起来(10)相关的知识,希望对你有一定的参考价值。
模型(Model)在Play应用中处于非常核心的地位,是应用对操作信息的特定域的表现形式。
Martin fowler做了如下的定义:模型层负责表示业务概念,业务状况的信息及其规则。尽管保存这些内容的技术细节由基础架构来完成,但反映了上述信息是在模型层中被控制和使用的,因而在软件业务开发当中处于非常核心的地位。
普遍使用的Java设计模式是尽可能地将模型定义为一些简单的Java Bean,然后将应用的业务逻辑放到用来操作这些模型的service层。在Play中,将这种传统的设计模式定义为反模式。
反模式:在开发、设计、管理中采用的糟糕的解决方案。
与优秀的改进型模式相反,反模式告诉我们应该尽量避免这些糟糕的模式而采用优秀的模式,以此起到警示作用。但反模式不是固定的,其中的“良好”或“糟糕”是对应于一定的环境而言的,因为一种良好的设计如果应用在错误的环境下也可能成为一种反模式。
Martin fowler将上述的这种反模式命名为贫血模型(Anemic object model):贫血域模型(Anemic Domain Model)最基本的表现是乍一看跟真实世界中的区别不大,有对象,有许多以名词命名的域空间。将这些对象与那些真实域模型进行对照,会发现两者在宏观的关系和结构方面有着紧密的联系。但美中不足的是当我们仔细观察其行为时,会意识到除了getXxx和setXxx方法以外很难发现有基于对象自身的操作。这些模型拥有约定俗成的设计规则:不要将业务逻辑放到域模型中,取而代之的是将这些逻辑交给上面的service层去处理,间接使用模型来对数据进行操作。
这个反模式最大的恐怖之处在于,它与面向对象设计中的基本概念背道而驰,因为它没有将数据和操作放在一起。贫血域模型实际上仅仅是面向过程的设计风格,而且这种设计风格是面向对象的设计者们所反对的。可现在的情况是很多人认为贫血对象就是真实的对象,因此完全错过了去挖掘面向对象设计究竟是怎么一回事的机会。
1、域模型属性模拟
查看Play提供的示例应用,模型类里面会频繁地使用声明为public的变量。即使是经验尚浅的Java开发者,也懂得慎用public类型的变量。在Java开发中(当然还有其他的面向对象语言),实践经验是这样告诉我们的:将所有的成员变量声明为私有,只提供获取与修改的方法。这样做的目的在于增强程序的封装性,而“封装”在面向对象设计中恰恰是非常关键的概念。
Java没有真正的内置属性定义机制,而是使用Java Bean来进行约束:Java对象的属性通过一对getXxx/setXxx的方法来修改,如果对象是只读的那么只需要提供getXxx方法。在过去的开发中我们一直这样做,但是编码过程就显得有些乏味了。每个属性必须声明为private,同时还有相应的getXxx/setXxx方法,而且大多数情况下,getXxx和setXxx方法的实现都是类似的。
private String name;
public String getName()
return name;
public void setName(String value)
name = value;
Play框架的模型部分会自动生成getXxx/setXxx方法,保持代码的简洁。也就是说,在Play中开发者可以直接把属性变量声明为public,运行时Play会自动生成相应的getXxx/setXxx方法(在这里我们将声明为public的字段都视为属性)。
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;
因为变量被声明为public,可以使用如下方式对属性进行操作:
product.name = "My product";程序在加载时会自动地转换成:
product.price = 58;
product.setName("My product");
product.setPrice(58);
因为这些getXxx/setXxx方法是在运行时动态生成的,所以不能直接调用。如果在编码阶段使用他们,编译器会因为找不到该方法而报错误。
当然也可以自己定义相应的getXxx/setXxx方法,Play会优先选择手动编写的方法。如果需要保护Product类的price属性就可以定义setPrice()方法:
public class Product如果为Product类的price属性赋负值就会抛出异常:
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! IllegalArgumentExceptionPlay总会优先使用已经定义的getXxx/setXxx方法:
@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;
@Entity注解的作用是通知Play自动开启JPA实体管理器,@Required是对该属性的约束。该类继承于play.db.jpa.Model,Model提供了非常简单的对象处理方式,在后面章节会做详细介绍。
针对以上例子可以进行如下测试断言:
Data data = new Data();以上的断言都会执行通过,而且因为这种改进的类遵从JavaBean规范,可以满足开发中的更复杂需求。
data.anotherValue = null;
assert data.anotherValue == 0;
data.anotherValue = 4
assert data.anotherValue == 8;
2、数据库配置
通常情况下,开发者需要将模型对象持久化。最常用的方法是把这些数据保存到数据库中。
在Play应用的开发过程中,开发者可以迅速配置嵌入式内存数据库或者直接将数据保存到文件系统中。开启内存数据库H2,只需要在conf/application.conf文件中进行如下配置:
db=mem
H2是开放源代码的Java数据库,其具有标准的SQL语法和Java接口,可以自由使用和分发,且非常简洁和快速。将数据保存在内存中相比从磁盘上访问能够极大地提高应用的性能,但由于内存容量的限制,内存数据库适用于开发阶段,或者原型示例开发。
如果需要将数据保存在文件系统中,则使用如下配置:
db=fs如果需要连接到mysql服务器,则使用如下配置:
db=mysql:user:pwd@database_name
Play框架集成了H2数据库和MySQL数据库的驱动程序,存放在$PLAY_HOME/framework/lib/目录下。如果需要使用PostgreSQL,Oracle或者其他数据库,需要在该目录(或者应用程序的lib/目录)下添加相应的数据库驱动。
Play可以连接任何JDBC兼容的数据库,只需要将相应的驱动类库添加到/lib目录中,并在conf/application.conf文件中定义JDBC配置:
db.url=jdbc:mysql://localhost/test还可以在conf/application.conf文件中用配置选项指定JPA方言:
db.driver=com.mysql.jdbc.Driver
db.user=root
db.pass=123456
play框架使用起来(17)