项目越做越大,代码越来越多。陆续出了一些问题。
1、action层代码过多,复用性不强。往往多个应用要使用同一个功能。如A应用中有发布感受,B应用中也需要,这时B就把A中action的代码复制过来。
2、一个功能比较复杂,调用service比较多。发布文章前要判断是否黑名单,是否有违禁词,然后持久化,然后发积分和站内信等。现在全部写在一起,修改困难,不灵活。
重构目标:
1、新建Biz层,该层负责调用各单一小模块实现一个复杂功能。该层可打成jar包或发布成SOA,供其他方调用。
2、其他应用中如果也要发感受功能,但需要改一个小位置。如发积分策略,将新增自己的发积分模块并注入该Biz即可,影响小。
附上代码
package com.my.biz;
/**
*
* 描述
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public interface IBiz {
Object[] execute(Object ... objects );
}
package com.my.biz;
import java.util.List;
import com.my.domain.Review;
/**
*
* 描述 这是发布感受的处理流程
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class InsertReviewBiz implements IBiz{
//初始化信息
private List<IBizHandler<Review>> initInfoHandlers;
//验证信息
private List<IBizHandler<Review>> validateHandlers;
//安全检查
private List<IBizHandler<Review>> securityCheckHandlers;
//持久化
private List<IBizHandler<Review>> saveHandlers;
//持久化后操作
private List<IBizHandler<Review>> afterSaveHandlers;
/**
* objects[0] = review;
*/
@Override
public Object[] execute(Object... objects) {
// TODO Auto-generated method stub
BizUtil.exetureHandler(initInfoHandlers, (Review)objects[0]);
BizUtil.exetureHandler(validateHandlers, (Review)objects[0]);
BizUtil.exetureHandler(securityCheckHandlers, (Review)objects[0]);
BizUtil.exetureHandler(saveHandlers, (Review)objects[0]);
BizUtil.exetureHandler(afterSaveHandlers, (Review)objects[0]);
return objects;
}
public void setInitInfoHandlers(List<IBizHandler<Review>> initInfoHandlers) {
this.initInfoHandlers = initInfoHandlers;
}
public void setValidateHandlers(List<IBizHandler<Review>> validateHandlers) {
this.validateHandlers = validateHandlers;
}
public void setSecurityCheckHandlers(
List<IBizHandler<Review>> securityCheckHandlers) {
this.securityCheckHandlers = securityCheckHandlers;
}
public void setSaveHandlers(List<IBizHandler<Review>> saveHandlers) {
this.saveHandlers = saveHandlers;
}
public void setAfterSaveHandlers(List<IBizHandler<Review>> afterSaveHandlers) {
this.afterSaveHandlers = afterSaveHandlers;
}
}
package com.my.biz;
/**
*
* 描述
*
* @author 锅巴
* @version 1.0 2010-8-26
* @param <T>
*/
public interface IBizHandler<T> {
void execute(T t);
}
package com.my.biz;
import java.util.List;
/**
*
* 描述
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public final class BizUtil {
private BizUtil(){
}
static <T> void exetureHandler(List<IBizHandler<T>> bizHandlers,T t){
for(IBizHandler<T> bizHandler : bizHandlers){
bizHandler.execute(t);
}
}
}
以下是各处理handler的实现
package com.my.biz.handler;
import com.my.biz.IBizHandler;
import com.my.domain.Review;
import com.my.domain.model.ITargetRepository;
/**
*
* 初始化感受
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class InitReviewHandler implements IBizHandler<Review>{
private ITargetRepository targetRepository;
public void execute(Review review){
review.setTargetSubCategory(targetRepository.
findTarget(review.getTargetId()).getSubCategroy());
}
public ITargetRepository getTargetRepository() {
return targetRepository;
}
public void setTargetRepository(ITargetRepository targetRepository) {
this.targetRepository = targetRepository;
}
}
package com.my.biz.handler;
import org.springframework.util.Assert;
import com.my.biz.IBizHandler;
import com.my.domain.Review;
/**
*
* 验证感受对象数据
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class ValidateReviewHandler implements IBizHandler<Review>{
@Override
public void execute(Review review) {
// TODO Auto-generated method stub
Assert.isTrue(review != null);
Assert.isTrue(review.getContent() != null);
Assert.isTrue(review.getUserId() > 0);
Assert.isTrue(review.getTargetId() != null);
Assert.isTrue(review.getTargetSubCategory() != null && review.getTargetSubCategory().size() > 0);
}
public static void main(String[] args) {
Review review = null;
Assert.isNull(review);
System.out.println(" end ");
}
}
package com.my.biz.handler;
/**
*
* 安全处理
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class SecurityCheckException extends RuntimeException{
/**
*
*/
private static final long serialVersionUID = 1L;
public SecurityCheckException(String content){
super(content);
}
public static void main(String[] args) throws Exception{
throw new SecurityException("含有违禁词");
}
}
package com.my.biz.handler;
import com.my.biz.IBizHandler;
import com.my.domain.Review;
import com.my.domain.model.IReviewRepository;
/**
*
* 持久化感受
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class SaveReviewHandler implements IBizHandler<Review>{
private IReviewRepository reviewRepository;
@Override
public void execute(Review t) {
// TODO Auto-generated method stub
reviewRepository.create(t);
}
public IReviewRepository getReviewRepository() {
return reviewRepository;
}
public void setReviewRepository(IReviewRepository reviewRepository) {
this.reviewRepository = reviewRepository;
}
}
package com.my.biz.handler;
import com.my.biz.IBizHandler;
import com.my.domain.Review;
/**
*
* 发消息
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class AfterSaveReviewSendNotifyHandler implements IBizHandler<Review>{
@Override
public void execute(Review t) {
// TODO Auto-generated method stub
StringBuilder str = new StringBuilder();
str.append("id:" + t.getId() + " ")
.append("targetId:" + t.getTargetId() + " ")
.append("content:" + t.getContent() + " ");
System.out.println(" send notify : " + str.toString());
}
}
package com.my.biz.handler;
/**
*
* 安全处理不通过异常
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class SecurityCheckException extends RuntimeException{
/**
*
*/
private static final long serialVersionUID = 1L;
public SecurityCheckException(String content){
super(content);
}
}
以下是domain
package com.my.domain;
import java.util.Date;
import java.util.Set;
/**
*
* 感觉对象
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class Review {
private String id;
private String content;
private String targetId;
private Set<Integer> targetSubCategory;
private int userId;
private Date createTime;
public String getId() {
return id;
}
public String getContent() {
return content;
}
public String getTargetId() {
return targetId;
}
public int getUserId() {
return userId;
}
public Date getCreateTime() {
return createTime;
}
public void setId(String id) {
this.id = id;
}
public void setContent(String content) {
this.content = content;
}
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Set<Integer> getTargetSubCategory() {
return targetSubCategory;
}
public void setTargetSubCategory(Set<Integer> targetSubCategory) {
this.targetSubCategory = targetSubCategory;
}
}
package com.my.domain;
import java.util.Set;
/**
*
* 发布感受的对象,如店铺
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class Target {
private String id;
private Set<Integer> subCategroy;
public String getId() {
return id;
}
public Set<Integer> getSubCategroy() {
return subCategroy;
}
public void setId(String id) {
this.id = id;
}
public void setSubCategroy(Set<Integer> subCategroy) {
this.subCategroy = subCategroy;
}
}
package com.my.domain.model;
import com.my.domain.Review;
/**
*
* 感觉对象仓库
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public interface IReviewRepository {
Review create(Review review);
}
package com.my.domain.model;
import com.my.domain.Target;
/**
*
* 感受目标对象仓库
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public interface ITargetRepository {
Target findTarget(String targetId);
}
package com.my.infrastructure.persistence;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.my.domain.Review;
import com.my.domain.model.IReviewRepository;
/**
*
* 用ibatis实现的感受仓库
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class ReviewRepositoryIbatis implements IReviewRepository{
@Override
public Review create(Review review) {
// TODO Auto-generated method stub
review.setId(String.valueOf(Math.random()));
review.setCreateTime(new Date());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("persistence review . id :" + review.getId() + " create date: " + format.format(review.getCreateTime()));
return review;
}
}
package com.my.infrastructure.persistence;
import java.util.HashSet;
import java.util.Set;
import com.my.domain.Target;
import com.my.domain.model.ITargetRepository;
/**
*
* 用ibatis实现的感受目标对象仓库
*
* @author 锅巴
* @version 1.0 2010-8-26
*/
public class TargetRepositoryIbatis implements ITargetRepository{
@Override
public Target findTarget(String targetId) {
// TODO Auto-generated method stub
Target target = new Target();
target.setId(targetId);
Set<Integer> set = new HashSet<Integer>();
set.add(52);
set.add(36);
set.add(68);
target.setSubCategroy(set);
System.out.println("target find ");
return target;
}
}
spring 配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
<!--
- Application context definition.
-->
<beans>
<bean id="reviewRepository" class="com.my.infrastructure.persistence.ReviewRepositoryIbatis"/>
<bean id="targetRepository" class="com.my.infrastructure.persistence.TargetRepositoryIbatis"/>
<bean id="initReviewHandler" class="com.my.biz.handler.InitReviewHandler">
<property name="targetRepository">
<ref bean="targetRepository"/>
</property>
</bean>
<bean id="validateReviewHandler" class="com.my.biz.handler.ValidateReviewHandler"/>
<bean id="securityCheckReviewHandler" class="com.my.biz.handler.SecurityCheckReviewHandler"/>
<bean id="saveReviewHandler" class="com.my.biz.handler.SaveReviewHandler">
<property name="reviewRepository">
<ref bean="reviewRepository"/>
</property>
</bean>
<bean id="afterSaveReviewSendNotifyHandler" class="com.my.biz.handler.AfterSaveReviewSendNotifyHandler"/>
<bean id="insertReviewBiz" class="com.my.biz.InsertReviewBiz">
<property name="initInfoHandlers">
<list>
<ref bean="initReviewHandler"/>
</list>
</property>
<property name="validateHandlers">
<list>
<ref bean="validateReviewHandler"/>
</list>
</property>
<property name="securityCheckHandlers">
<list>
<ref bean="securityCheckReviewHandler"/>
</list>
</property>
<property name="saveHandlers">
<list>
<ref bean="saveReviewHandler"/>
</list>
</property>
<property name="afterSaveHandlers">
<list>
<ref bean="afterSaveReviewSendNotifyHandler"/>
</list>
</property>
</bean>
</beans>
junit测试
package com.my.biz;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.my.domain.Review;
public class BizTest {
ApplicationContext context = null;
IBiz insertReviewBiz = null;
@Before
public void setContent(){
context = new ClassPathXmlApplicationContext(new String[]{"conf/review.context.xml"});
insertReviewBiz = (IBiz)context.getBean("insertReviewBiz");
}
@Test
public void testRunBiz(){
try{
Review review = new Review();
review.setTargetId("8");
review.setContent("888899897");
review.setUserId(5);
insertReviewBiz.execute(review);
}catch(Exception e){
e.printStackTrace();
}
}
}
各个模块都是注入的,Biz层只需要保证大的流程及执行顺序即可。具体实现推迟到handler中,通过增加新的hanlder更改配置文件就可以实现不同的需求。
代码实现比较仓促,希望指教。