`
weilJava
  • 浏览: 70022 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

模板模式——类似业务的代码整合

 
阅读更多
    最近在开发客服第三方支付功能的时候,发现了主从表分页查询存在问题,然后解决了这个问题后,想将修改后的核心代码迁移到itv、短代、游戏包历史订购等相关接口时,发现这个完全适用于模板模式。好处就是当有类似的主从表分页查询时,只需要继承父类,实现相应的dao方法即可
先贴一个模板模式的图
[img]图在最下面,不会排版:funk: [img]
先说明下使用场景:因为数据量过大,所以在mysql对表进行了按月切分(并且是跨库),那么分页查询这些表时就有点蛋疼了,下面使用java代码来做下分页(有其他更好的方案请各位提供,一定感谢)
先来做一个abstract类

package cn.egame.data.core.common;

import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.model.PageData;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by dinghw on 2015/4/20.
 *
 * @desc 此类为模板模式的抽象类,主要用于主从分表查询分页的方法
*/
public abstract class TablesTemplate<B> {
    Logger logger = Logger.getLogger(TablesTemplate.class);
    /**
     * 模板方法的子类必须为此dao赋值,并且相应的类必须实现{@link TemplateOnlineServiceDao}
     */
    public TemplateOnlineServiceDao templateOnlineServiceDao;

    public TemplateOfflineServiceDao templateOfflineServiceDao;

    /**
     * @param bean     查询条件对象
     * @param currPage
     * @param pageSize
     * @param <T>      返回对象
     * @return
     * @throws ExceptionCommonBase
     */
    public <T> PageData getPageDataFromOnlineAndOffline(B bean, int currPage, int pageSize) throws ExceptionCommonBase {
        int totalCount = 0;
        PageData pageData = templateOnlineServiceDao.getPageDataFromOnline(bean, currPage, pageSize);
        int onlineTotalCount = pageData.getTotal();
        totalCount += onlineTotalCount;
        List<String> tableNames = templateOfflineServiceDao.getOfflineTables();
        List<T> pageList = (List<T>) pageData.getContent();
        for (String tableName : tableNames) {
            try {
                int offlineTotalCount = templateOfflineServiceDao.totalCount(bean, tableName);
                if (offlineTotalCount == 0) continue;
                int indexNum = (currPage - 1) * pageSize + 1;
                int endNum = currPage * pageSize;
                if (totalCount >= endNum) {
                    totalCount = totalCount + offlineTotalCount;
                    continue;
                }
                List<T> offlineTableList = templateOfflineServiceDao.listFromOffline(bean, tableName);
                List<T> tempList = getSubList(offlineTableList, pageSize, totalCount, offlineTotalCount, indexNum, endNum);
                pageList.addAll(tempList);
                totalCount = totalCount + offlineTotalCount;
            } catch (ExceptionCommonBase e) {
                logger.error(e.getMessage(), e);
            }
        }
        pageData.setContent(pageList);
        pageData.setTotal(totalCount);
        return pageData;
    }

    /**
     * 分页,获取从表的数据并切分
     *
     * @param offlineTableList
     * @param pageSize
     * @param totalCount
     * @param offlineTotalCount
     * @param indexNum
     * @param endNum
     * @return
     */
    private <T> List<T> getSubList(List<T> offlineTableList, int pageSize, int totalCount, int offlineTotalCount, int indexNum, int endNum) {
        if (offlineTableList == null || offlineTableList.size() == 0) {
            return new ArrayList();
        }
        int fromIndex = 0;
        int toIndex = 0;
        if (totalCount >= indexNum) {
            if ((totalCount + offlineTotalCount) > endNum) {
                toIndex = endNum - totalCount;
            } else {
                toIndex = offlineTotalCount;
            }
        } else if (totalCount < indexNum && (totalCount + offlineTotalCount) >= indexNum) {
            fromIndex = indexNum - 1 - totalCount;
            if ((totalCount + offlineTotalCount) >= endNum) {
                toIndex = fromIndex + pageSize;
            } else {
                toIndex = offlineTotalCount;
            }
        }
        return offlineTableList.subList(fromIndex, toIndex);
    }
}



上面代码实现规则:先从主表中取数据,然后依次从从表中查询表的总数,当满足当前页的数据则加入到tempList中,直至加满(=pageSize),如果数据不满足则不做处理

其中TemplateOnlineServiceDao、TemplateOfflineServiceDao 均为接口提供方法如下

package cn.egame.data.core.common;

import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.model.PageData;
import cn.egame.data.model.itv.ItvFee;
import cn.egame.data.model.itv.ItvFeeBean;

import java.util.List;


/**
 * Created by dinghw on 2015/4/20.
 */
public interface TemplateOnlineServiceDao<B> {

    /**
     * @param bean
     * @param currPage
     * @param pageSize
     * @return
     * @throws ExceptionCommonBase
     * @throws ExceptionCommonBase
     */
    public <T> PageData getPageDataFromOnline(B bean, int currPage, int pageSize) throws ExceptionCommonBase;


    /**
     * @param bean
     * @param <T>
     * @return
     * @throws ExceptionCommonBase
     */
    public <T> List<T> listFromOnline(B bean) throws ExceptionCommonBase;

}




package cn.egame.data.core.common;

import cn.egame.common.exception.ExceptionCommonBase;

import java.util.List;

/**
 * Created by dinghw on 2015/4/20.
 */
public interface TemplateOfflineServiceDao<B> {

    /**
     * 获取线下所有表名
     *
     * @return
     * @throws cn.egame.common.exception.ExceptionCommonBase
     */
    public List<String> getOfflineTables() throws ExceptionCommonBase;

    /**
     * 获取表中的总数
     *
     * @param bean
     * @param tableName
     * @return
     * @throws ExceptionCommonBase
     */
    public int totalCount(B bean, String tableName) throws ExceptionCommonBase;

    /**
     * 查询出线下库表的数据
     *
     * @param bean
     * @param tableName
     * @param <T>       返回类型
     * @return
     * @throws ExceptionCommonBase
     */
    public <T> List<T> listFromOffline(B bean, String tableName) throws ExceptionCommonBase;
}



这边TemplateOfflineServiceDao类中getOfflineTables方法,其实可以放到抽象类TablesTemplate,因为这个方法在一定程度上属于service层而不是dao层


上层的架子搭好了,下面就是具体的实现了,拿itv的代码做例子

/**
 *
 */
package cn.egame.data.core.itv;

import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.model.PageData;
import cn.egame.data.core.app.AppServiceFactory;
import cn.egame.data.core.common.TablesTemplate;
import cn.egame.data.core.common.TemplateOfflineServiceDao;
import cn.egame.data.core.common.TemplateOnlineServiceDao;
import cn.egame.data.core.cp.CpServiceFactory;
import cn.egame.data.interfaces.IObjectVisitor;
import cn.egame.data.interfaces.ItvFeeService;
import cn.egame.data.model.ContentProvider;
import cn.egame.data.model.app.AppConsume;
import cn.egame.data.model.app.AppInfo;
import cn.egame.data.model.itv.ItvFee;
import cn.egame.data.model.itv.ItvFeeBean;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

/**
 * itv计费相关业务实现类
*
 * @author houqq
 * @date 2014年11月28日 上午9:43:22
 */
public class ItvFeeServiceImpl extends TablesTemplate<ItvFeeBean> implements ItvFeeService {
    Logger logger = Logger.getLogger(ItvFeeServiceImpl.class);

    private static ItvFeeServiceImpl instance;

    private static byte[] syncRoot = new byte[1];

    private ItvFeeServiceDao itvFeeServiceDao;
    private ItvFeeOfflineDao itvFeeOfflineDao;

    private ItvFeeServiceImpl() throws ExceptionCommonBase {
        itvFeeServiceDao = new ItvFeeServiceDao();
        itvFeeOfflineDao = new ItvFeeOfflineDao();
        templateOnlineServiceDao = new ItvFeeServiceDao();
        templateOfflineServiceDao = new ItvFeeOfflineDao();
    }

    public static ItvFeeServiceImpl getInstance() throws ExceptionCommonBase {
        if (instance == null) {
            synchronized (syncRoot) {
                if (instance == null) {
                    instance = new ItvFeeServiceImpl();
                }
            }
        }
        return instance;
    }

    
    /**
     * 依据条件查询itv计费列表
     *
     * @param itvFeeBean itv计费实体
     * @return itv计费列表
     * @throws ExceptionCommonBase
     */
    private List<ItvFee> listItvFee(ItvFeeBean itvFeeBean) throws ExceptionCommonBase {
        List<ItvFee> itvFees = itvFeeServiceDao.listFromOnline(itvFeeBean);
        List<ItvFee> offLineItvFees = itvFeeOfflineDao.listAllFromOffline(itvFeeBean);
        itvFees.addAll(offLineItvFees);
        return itvFees;
    }


    /**
     * 从主从表中获取数据
     *
     * @param appId
     * @param userId
     * @param itvfeebean
     * @param currPage
     * @param pageSize
     * @return
     * @throws RemoteException
     */
    public PageData listItvFee(int appId, long userId, ItvFeeBean itvfeebean, int currPage, int pageSize) throws RemoteException {
        if (StringUtils.isEmpty(itvfeebean.getLinkageAccountId()) && StringUtils.isEmpty(itvfeebean.getPhone())) {
            PageData pageData = new PageData();
            pageData.setCurrentPage(currPage);
            pageData.setRowsOfPage(pageSize);
            return pageData;
        }
        //此处调用父类方法
        return this.getPageDataFromOnlineAndOffline(itvfeebean, currPage, pageSize);
    }
}


上述代码有一个让我感觉还不够完美的地方,就是dao定义,我必须得重复定义,一方面为了兼容之前的方法,另外一方面,较少TemplateOnlineServiceDao、TemplateOfflineServiceDao两个接口中的方法数量,让子类的dao可存在自己的特性方法

        itvFeeServiceDao = new ItvFeeServiceDao();
        itvFeeOfflineDao = new ItvFeeOfflineDao();
        templateOnlineServiceDao = new ItvFeeServiceDao();
        templateOfflineServiceDao = new ItvFeeOfflineDao();



  • 大小: 9.6 KB
分享到:
评论

相关推荐

    JavaWeb课程设计——图书馆管理系统.pdf

    其次,让学生初识并运用设计模式,如GoF(Gang of Four,设计模式四人组)提出的单例模式和模板方法模式,提高代码的可读性和可维护性;最后,整合数据库,实现图书管理的各项功能,如图书的入库、报废,借书证的...

    IntelliJ IDEA基于SSM框架整合开发模板带用户增删改查分页功能源代码

    SSM框架是Java Web开发中常用的三大组件——Spring、Struts2和MyBatis的组合,常用于构建大型企业级应用。在这个项目中,`IntelliJ IDEA`作为强大的Java集成开发环境,被用来进行整个项目的开发与管理。 **Spring...

    简单的应用代码1

    提到“很好的参考作用”,意味着这些代码是具有实践价值的,可以作为模板或者参照来解决类似问题。此外,“以后会继续上传更新”则暗示这是一个动态的项目,作者可能会定期添加新功能、修复错误或改进现有代码,这为...

    UML设计模式

    例如策略模式、模板方法模式、观察者模式、命令模式、迭代器模式、解释器模式、中介者模式、备忘录模式、状态模式、访问者模式和责任链模式。 设计模式的应用能够提高代码的可读性、可维护性和可扩展性,同时减少...

    ASP.NET源码——[博客空间]BruceBlog程序源码(采用NHibernate).zip

    【标题】"ASP.NET源码——[博客空间]BruceBlog程序源码(采用NHibernate).zip" 提供的是一个基于ASP.NET技术开发的博客系统源代码,该系统使用了NHibernate作为持久化框架。这个博客平台是开发者Bruce创建的一个项目...

    ssh框架的第二部分

    - **HQL(Hibernate Query Language)**:类似SQL的查询语言,用于在Java代码中查询数据库。 4. **SSH整合**: - **配置整合**:在Spring配置文件中定义Struts的Action和Hibernate的SessionFactory,实现三者的...

    C# 3.0与.NET 3.5高级编程.pdf

    WF支持状态机、顺序流程、活动库和规则引擎等多种工作流模式,可以轻松处理复杂的业务逻辑。WF与WCF和WPF等.NET组件紧密集成,能够构建出具有强大工作流支持的应用程序。 通过学习《精通C# 3.0与.NET 3.5高级编程》...

    最全SSH笔记汇总

    SSH,是Java Web开发中的三大框架——Struts、Hibernate和Spring的缩写,这三大框架在Web应用程序开发中起着核心支撑作用。本篇笔记汇总将深入探讨这三个框架的原理、配置与应用。 首先,Struts2是MVC(Model-View-...

    struts2写的用户管理

    通过这个项目,你可以学习到如何利用Struts2和Hibernate进行基本的Web开发,理解MVC模式,以及在实际应用中如何处理用户管理相关的业务需求。同时,这也为你提供了实践Struts2拦截器、参数校验、页面交互等技术的...

    青鸟租房网,使用了Hibernate+Struts框架

    本文将深入探讨该系统背后的技术实现——Hibernate和Struts2框架的集成应用。 Hibernate,作为Java领域中的一个持久化框架,它简化了数据库操作,使得开发者无需关注SQL语法,而是通过对象关系映射(ORM)来处理...

    集成Hibernate3.6.8+Spring3.0.6+struts2.2.3.0

    标题中的"集成Hibernate3.6.8+Spring3.0.6+struts2.2.3.0"指的是一个经典的Java Web开发框架整合,它将三个强大的开源框架——Hibernate、Spring和Struts2结合在一起,以实现高效、模块化且可维护的Web应用程序。...

    指纹仪二次开发

    维尔公司推出的U4000b指纹仪是此类设备中的代表,它提供了强大的硬件支持以及易于集成的二次开发接口,使得开发者可以轻松地将指纹识别功能整合到自己的应用程序中。本篇我们将深入探讨"指纹仪二次开发"这一主题,...

    Research and Application of Hibernate in Spring

    - **查询语言**:Hibernate提供了自己的查询语言——HQL(Hibernate Query Language),这是一种类似于SQL的语言,但它是面向对象的,更加直观易懂。 - **缓存机制**:为了提高性能,Hibernate内部提供了一级缓存和...

    某铜业集团公司全面Intranet的构建

    ### 某铜业集团公司全面Intranet的构建 #### 一、背景介绍 某铜业集团公司成立于1996年,是中国有色金属工业总公司为了组建大型企业集团而成立...此外,本案例的成功经验也为其他类似企业提供了一个有价值的参考模板。

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    过去,网络软件的开发都采用C/S(client)模式,在这种模式下,主要的业务逻辑都集中于客户端程序,因此,必然导致以下问题: 系统安装、调试、维护和升级困难。由于客户端的硬件配置可能存在差异,软件环能各不相同...

Global site tag (gtag.js) - Google Analytics