智慧領域物件設計(演繹革命)-1/2

cuwkuhaihong發表於2010-08-08
請先看看:智慧領域物件設計

本文原始碼
關於智慧領域物件的設計,一直沒有拿出確實的例子來說明這樣程式設計的好處和優點,以及如何正確地理解這種程式設計方式。接下來我開始從傳統Service + DAO開發模式開始改造和發展,直到變化成智慧領域物件設計的開發模式上來,對於每一種變化,我會統計出手工程式碼編寫行數(setter 、getter和import等就不在統計範圍內了),看看生產力的變化。任何生產力的提高都是體現在機械代替重複而又規律的工作上,我們選擇的案例同樣是本應該被工業化掉的東西,但還在手工勞作。
傳統的Service + DAO包括三個核心類,以“使用者”物件為例,通常包括的類:User, UserService, UserDAO。通常需要的外部支援是:hibernate/jpa,spring。為了演示方便忽略掉介面(如IUserService),也不再區分PO和VO。事實上案例演示完成後,你會發覺這兩個東西確實很少使用。
這個例項中包含了一個持久層框架Thin,我先將有關持久的論述寫在這裡,你可以先看例項回頭有興趣再這段內容:所謂物件的持久就是把物件的屬性登記在資料庫中,在現實生活是經常發生的,如我們去銀行辦一個儲蓄卡,需要填表,而填表的過程就是持久化的過程。看看這張表格,便會發現所有填寫項都可以用key-value表示,再考察我們是如何區分現實物件,便會發現同樣是以物件的屬性為區分依據,屬性就可以用key-value表示,所以無論任何物件只要被持久必然可轉化成key-value,唯一的不同就是key-value的儲存方法不同而已,即:key-value是一切物件持久的介面。如果應用程式的持久方式是基於key-value的,那麼這種應用不僅便於更換不同的關聯式資料庫,即使是往NO-SQL資料庫上移植,縱然我對No-SQL資料庫不甚瞭解,但它絕不會偏離本質。Thin就是這麼一個工具,把物件轉化成key-value,然後存入對應的表,反之亦可。科學家通常用習慣用“美”來衡量結論正確性,雖然沒有什麼科學依據,但也屢試不爽。key-value是一切物件持久的介面,這個結論是美的,大家可以順便考量一下thin的短小精幹是否也符合美的標準。”大道若簡”,我相信基於key-value的持久方式,正是持久層的“大道”。
User類改動前User.java:

@Entity
@Table(name=”user”)
public class User{
	@Id
	private String uid;
	private String uname;
	private String password;
	private String gid;//機構ID
	private String gname;//機構名稱
	private String rid;//角色ID
	private String rname;//角色名稱

	//setter and getter	
}

UserService.java

/**
 * spring的配置忽略
 * 
 * <bean id="UserService" class="com.icitic.zero.service.impl.UserService">
      <property name="userDao" ref="userDao"/>
   </bean>    
    
 * @author haihong
 *
 */
public class UserService {
    private UserDAO userDao;
    public void addUser(User user) {
		try {
			this.userDao.add(user);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
   public User getUser(String id) {
		try {
			this.userDao.getUserById(id);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return null;
	}

	public void updateUser(User user) {
		try {
			this.userDao.update(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void deleteUser(Collection<User> users) {
		try {
			User[] us = new User[users.size()];
			users.toArray(us);
			this.userDao.delete(us);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void saveOrUpdate(User user) {
		try {
			this.userDao.save(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public UserDAO getUserDao() {
		return userDao;
	}
	public void setUserDao(UserDAO userDao) {
		this.userDao = userDao;
	}	
}
UserDAO.java
/**
 *  <bean id="UserDAO" class="com.icitic.zero.dao.UserDAO">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
 * 
 * 
 * @author haihong
 *
 */
public class UserDAO extends HibernateDaoSupport{
	public void add(User user) {
		getHibernateTemplate().save(user);
	}
    public User getUserById(String id) {
		return (User) getHibernateTemplate().load( User.class, id);
	}
	public void update(User user) {
		getHibernateTemplate().update(user);
	}
	public void delete(User... user) {
		getHibernateTemplate().delete(user);
	}
	public void deleteById(String uid) {
		User user = this.getUserById(uid);
		getHibernateTemplate().delete(user);
	}
	public void save(User user) {
		getHibernateTemplate().saveOrUpdate(user);
	}
}

<p class="indent">


1.編碼量統計:
User.java 11行
UserService.java 56行
UserDAO.java 21行
共88行


開始用thin(基於key-value的持久層框架)改造:
User.java

@BeanTableName(name="z_user")
public class User{
	@Primary
	private String uid;
	private String uname;
	private String password;
	private String gid;//機構ID
	private String gname;//機構名稱
	private String rid;//角色ID
	private String rname;//角色名稱
//setter and getter
}

<p class="indent">

替換類和主鍵的註解換成thin的註解,其他不變.
UserService.java

public class UserService extends BaseService  {
	public void addUser(User user) {
		try {
			this.add(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public User getUser(String id) {
		try {
			List users = this.getObject(User.class,SQLCriterion.get("uid", id));
			if(users.isEmpty()){
				return (User)users.get(0);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	public void deleteUser(User user) {
		try {
			this.deleteObject(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void deleteUser(String uid) {
		try {
			User user = (User)this.getObject(User.class, SQLCriterion.get("uid", uid));
			this.deleteUser(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void deleteUser(Collection<User> users) {
		Collection<String> uids = new ArrayList();
		for (User u : users) {
			uids.add(u.getUid());
		}
		try {
			getBeanTable(User.class).delete(SQLCriterion.get("uid", Operator.IN, uids));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void saveOrUpdate(User user) {
		try {
			ThinContext.ctx.beginTransaction();
			this.deleteUser(user);
			this.addUser(user);
			ThinContext.ctx.commitTransaction();
		} catch (SQLException e) {
			try {
				ThinContext.ctx.rollback();
			} catch (SQLException e1) {
			}
			throw new RuntimeException(e);
		}
	}
}

<p class="indent">

UserDAO.java不再需要,所有類似與此的DAO都不需要了,BaseService 已經為物件的持久提供好了介面,只需要呼叫即可。


2.編碼量統計:
User.java 11行
UserService.java 60行
UserDAO.java 0行
編碼量合計:71行


如此改進會減少88-71=17行程式碼和一個Dao類。
同時可以放一放hibernate/jpa這個朋友了,而且可以減少與spring的瓜葛。說真的,使用Service+DAO這種方式程式設計,有類似spring這樣的管理工具,還是真是輕鬆了不少,但是spring所提供的依賴管理方式只是讓我們更加舒適地適應了傳統,但是原來要寫程式現在幾乎還要寫。

我們再進一步用採用物件導向的思想(智慧領域物件設計)來改造這個模組,讓有User繼承ThinObject:

@BeanTableName(name="z_user")
public class DomainUser extends ThinObject{
	@Primary
	private String uid;
	private String uname;
	private String password;
	private String gid;//機構ID
	private String gname;//機構名稱
	private String rid;//角色ID
	private String rname;//角色名稱	
	//所有的增刪改查父類已經提供了
   //setter and getter
}
<p class="indent">

不再需要UserServiceT.java了,像這種增刪改查的功能,ThinObject已經提供了。


3.編碼量統計:
DomainUser.java 11行
UserServiceT.java 0行
UserDAO.java 0行
合計:11行


程式碼編寫量從88行降到11行。減少87.5%的工作量。以30類為例,就少寫2310行程式碼,少建60個類.
大家可以根據自己的工作效率算算,會節省多少天的工作量。從此單表的DAO操作就可以不用再寫,也不用建立對應增刪改查的類了。
當然這個例子有些極端,但是並不影響它在提高生產力的方面的不錯表現。讀到這裡你可以會有一個疑問,我們應該如何處理物件之間的關係,如一對多,或者多對多。複合物件是由簡單物件組成的,既然簡單的儲存已經很方便地解決了,複合物件也水到渠成地解決了。
智慧領域物件設計還有個特性,是支援因果事件模式,模擬因果傳遞。我在下一篇例項中詳解!

下一篇:智慧領域物件設計(例項講解)

[該貼被cuwkuhaihong於2010-08-09 13:20修改過]

相關文章