Seam 使用心得(二)接口實現

Java裏提倡使用面向接口編程以減弱組件之間的耦合,在上一篇裏已經定義了
@Local
public interface Register {
public String register();
}

這一節裏面將實現這個接口來通過測試。

現在應用系統有很多良好的分層方法,但是我還是喜歡Evans的領域驅動設計的方法。
1,視圖層將使用RichFaces。
2,使用無狀態SessionBean作爲Facade對領域邏輯進行封裝。
3,領域層實現核心業務邏輯,主要包括有實體,值對象,倉庫,服務等。

源文件目錄結構大致如下:
src
|----action (SLSB)
|----model (Service, Entity, Repository, Vo)
|----test
view
|----css
|----js
……

經過簡單的分析model層向facade暴露UserView接口
package org.qpt.domain.user;
import org.qpt.domain.user.User.RegState;
/**
* 用戶接口
* @author xiaoqiu
*/
public interface UserView {
String getConfirmPwd();
String getEmail();
String getName();
String getPwd();
/**
* 註冊一個新用戶
* @param ur 用戶倉庫接口
* @return 註冊結果狀態碼(共5種狀態,上一節已經提到過)
*/
RegState register(UserRepository ur);
void setConfirmPwd(String confirmPwd);
void setEmail(String email);
void setName(String name);
void setPwd(String pwd);
}


注:因爲EJB2嚴重的依賴於容器的基礎設施,如果在實體bean中包含業務邏輯,將很難進行測試,所以實體bean只能作爲數據容器,而背離面向對象的分析和設計方法。但是EJB3已經可以對實體進行透明持久化,並且很容易在容器外進行測試,所以就用User實體實現UserView接口,這裏用戶註冊的並沒有跨越多個實體,只涉及用戶實體,所以包含了業務方法register的User類代碼如下:

/**
* 用戶實體
*
* @author xiaoqiu
*/
@Entity
@Name("user")
@Scope(SESSION)
@Table(name = "users")
public class User implements Serializable, UserView {

private static final long serialVersionUID = 3836699581343986461L;
@Id
@NotNull
@Length(min = 6, max = 15)
private String name;
@NotNull
@Length(min = 6, max = 15)
private String pwd;
@Transient
private String confirmPwd;
@NotNull
@Email
private String email;
@Transient
private String confirmEmail;

public enum RegState {
EXISTS_EMAIL, EXISTS_NAME, PWD_NOT_EQ_IN_TWICE, EMAIL_NOT_EQ_IN_TWICE, SUCCESS
}

@Override
public RegState register(UserRepository ur) {
if (!pwd.equals(confirmPwd)) {
return PWD_NOT_EQ_IN_TWICE;
} else if (!email.equals(confirmEmail)) {
return EMAIL_NOT_EQ_IN_TWICE;
} else if (ur.findByProperty("name", name)) {
return EXISTS_NAME;
} else if (ur.findByProperty("email", email)) {
return EXISTS_EMAIL;
} else {
ur.save(this);
return SUCCESS;
}
}

……
get&set method
}

考慮到視圖層RichFaces和hibernate驗證結合可以進行很簡單的零腳本ajax驗證,所以本例子裏面使用了hibernate驗證。
由於register方法需要用的UserRepository來訪問數據庫,所以現在來看一下UserRepository接口。通過隔離基礎設施,這就是GOF設計模式中著名的Strategy模式,由於Java語言想要在實體中注入UserRepository在技術上存在困難,所以把UserRepository作爲方法的參數傳遞我個人認爲也是一種較爲簡潔的方法,而且通過接口的隔離不會和基礎設施產生強烈的耦合,UserRepository代碼如下:

/**
* 用戶倉庫接口
* @author xiaoqiu
*/
@Local
public interface UserRepository {
void save(User user);
User findByName(String name);
List<User> findAllUser();
/**
* 找出該屬性是否存在當前值
* @param name 屬性名
* @param value 屬性值
* @return 該屬性存在這個值返回true,否則返回false
*/
boolean findByProperty(String name, String value);
}


在本例裏面UserRepository的實現使用的JPA,這個接口的實現相當容易所以它的實現類UserRepositoryJPAImp代碼就不貼出來了,可以直接看提供的源碼。

model層的接口已經實現完畢,接下來實現facade,代碼如下:
@Stateless
@Name("register")
public class RegisterBean implements Register {

@Logger
private Log log;
@In
FacesMessages facesMessages;
@In
private UserView user;
@In("userRepository")
UserRepository ur;

public String register() {
RegState state = user.register(ur);
switch (state) {
case PWD_NOT_EQ_IN_TWICE:
log.info("the register state is " + state);
facesMessages.addFromResourceBundle("myapp.register.pwd.noteq");
break;
case EMAIL_NOT_EQ_IN_TWICE:
log.info("the register state is " + state);
facesMessages.addFromResourceBundle("myapp.register.email.noteq");
break;
case EXISTS_NAME:
log.info("the register state is " + state);
facesMessages.addFromResourceBundle("myapp.register.name.exists");
break;
case EXISTS_EMAIL:
log.info("the register state is " + state);
facesMessages.addFromResourceBundle("myapp.register.email.exists");
break;
case SUCCESS:
log.info("register a new user #{user.name}" + "\nthe register state is " + state);
facesMessages.addFromResourceBundle("myapp.register.success");
break;
}
return state.toString();
}
}

這裏facade是很薄的一層,不能包含任何業務邏輯,它主要根據model返回的狀態是向顯示層發送信息,使用facesMessages組件就可以很容易向Richfaces發送ajax驗證的響應信息,並且事務處理統一在facade層進行,由於使用EJB,所以就可以使用容器提供的事務管理。

上述類的結構如下圖所示:
facade: Register-->RegisterBean-->UserView&UserRepository
domain:UserView-->User(Eneity)<-->UserRepository-->UserRepositoryJPAImp
至此爲止,註冊用戶所需要的全部接口都已經實現,現在就可以用seam test命令來運行上一節寫好的測試代碼了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章