結合Meta Programming的OR Mapping - Active Record
像Ruby這種動態語言有個一般靜態語言較難達成的功能--Meta Programming。
它並不是什麼新技術,早在70年代的SmallTalk就有內建這玩意了,不過它的好處倒是在Ruby on Rails出現後,才紅了起來。
什麼是Meta Programming?
簡單說就是類別的定義可在執行期自由自在的修改…
可以在執行期對動態現存的類別新增、修改成員函式,也可以新增、修改成員變數...
舉例來說:
Date是一個Ruby提供的類別,而你需要在程式中判斷所指定的日期是不是假日,在一般靜態語言中你可能會新增一個全域函式,或是在你自己的Helper類別中加入一個函式,如下:
boolean isHoliday(Date theDay);
然後使用時是像這樣:
Date someDay = ...;
...
...
if (isHoliday(someDay)) {
....
}
...
嗯…較不直覺,不是嗎?
看看下列程式,如果可以這樣用呢?
if (someDay.isHoliday?()) {
...
}
是不是方便多了!!
如果你還不太了解的話,可以參考一下我之前寫的這篇Meta Programming簡介
當然Meta Programming的作用不止於此,它可以做出許多令人驚艷的應用,在Ruby on Rails中的Active Record就是使用此技術的殺手級應用之一。
Active Record是結合Meta Programming的OR Mapping框架,就像Java中的Hibernate一樣,但比它更好,在如此肯定的說他好之前,我們來回想一下Hibernate:
在資料庫中有一個Table: User,內容是使用者的資料,Schema如下:
create table products (
id int not null,
name varchar(100) not null,
age number,
primary key (id)
);
我希望使用物件的方式存取使用者的資料,使用Java+Hibernate時,我有以下幾個步驟:
1. 建立User.hbm.xml,做為OR Mapping的定義:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="richard.User" table="userinfo">
<id name="id" column="id" type="java.lang.Integer">
<generator class="assigned"/>
</id>
<property name="name" column="name" type="java.lang.String"/>
<property name="age" column="age" type="java.lang.Integer"/>
</class>
</hibernate-mapping>
2. 為物件中的欄位建立相對應的Getter和Setter:
package richard;
public class User {
private Integer id;
private String name;
private Integer age;
// 必須要有一個預設的建構方法
// 以使得Hibernate可以使用Constructor.newInstance()建立物件
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
3. 在Client端程式中如下列方法使用:
// Configuration 負責管理 Hibernate 配置訊息
Configuration config = new Configuration().configure();
// 根據 config 建立 SessionFactory
// SessionFactory 將用於建立 Session
SessionFactory sessionFactory = config.buildSessionFactory();
// 新增持久化的物件
User user = new User();
user.setId(new Integer(4));
user.setName("caterpillar");
user.setAge(new Integer(30));
// 開啟Session,相當於開啟JDBC的Connection
Session session = sessionFactory.openSession();
// Transaction表示一組會話操作
Transaction tx= session.beginTransaction();
// 將物件映射至資料庫表格中儲存
session.save(user);
// delete
User user2 = new User();
session.load(user2, 2);
session.delete(user2);
tx.commit();
session.close();
sessionFactory.close();
嗯!Hibernate還是不失為在Java上一個相當優良的OR Mapping工具,使用起來是很簡單易懂的,但還是有一些不方便的地方:
1. 必須定義XML檔,當Table很多,欄位也愈來愈多時會很難維護。
2. 必須為物件依照要操作的欄位定義Getter和Setter方法,同樣的,資料愈多愈難管。
3. 當物件之間有關聯時,會更難維護。
4. 每次設計有變更時,一連串要更新的地方都讓我想要離職。
這些都是目前OR Mapping難解的部分,很幸運的,如果你使用Ruby,現在就有個Active Record解決了這些問題:
Active Record是怎麼做的?
1. 你需要一個User類別,長這樣:
class User < ActiveRecord::Base
end
2. 使用方法如下:
# 可以用Active Record 新增一筆資料
user1 = User.new
user1.name="Richard"
user1.age=18
user1.save
# 也可以用Active Record來找一筆資料
user2 = User.find 1
print user2.name
我並沒有在User類別中定義屬性name, age,但就是直接可以用,我也沒有在User類別中定義類別方法(static method),但User.find()這個方法是work的。
很神奇嗎?
Active Record透過Meta Programming幫你把這些都加上去了,ORMapping變輕鬆了!!
沒有留言:
張貼留言