日期:2014-05-20  浏览次数:20810 次

新手来求教之四_一些设计上的疑惑
[color=#FF0000][/color]由于经验很少,所以每每遇到程序设计时总是很伤头脑,而最终也往往只能整出个差劲的设计来。
问题1:我设计的常用模块(比如控制台打印、字符集转换过滤、格式化日期、日志文件读写、properties文件读写、javaMail、jsonString读取、excel读取、验证码生成)等等模块经常用私有化构造方法+全部静态化方法来设计这些工具类,这样使用起来就是类名+方法名来使用,请问这种设计方法有何利弊?(tij里曾说过:当你的程序充斥着过多的static时,或许你该想想换个设计了,且实际调用起来越看越像面向过程,虽然用起来时确实方便,不用新建实例)
问题2:我的设计中经常用到抽象类,但却极少用到接口,这正常么?(我的理解是:接口就是抽象类更纯粹的一种表现,但意义是一样的,就是规范了一系列对象的所有动作,使使用这些服务的调用端可以和实际的实现相分离。)
问题3:我为程序中的业务模型层、dao层分别建立了一个工厂,这个工厂以业务模型的名称或代号为参数,以switch\catch的方式去判断并返回所求的实例,但总觉得switch\catch相当臃肿,也觉得,工厂模式除了将对象的创建工作集中到了一处进行统一管理的同时,工厂自己也是够复杂的,尤其是什么工厂方法模式和抽象工厂模式。
-------------------------------------------------------------------------
希望各位前辈能发表下对我这些看法、想法和设计思想的建议和批判,由于程序规模一直不大,且一直没有涉及到过多的修改和扩展,所以无法体会到当前设计是否足够方便扩展和修改。

------解决方案--------------------
接口比抽象类更应该值得取用:
抽象类的优势是子类继承父类方法,这是选择抽象类大于接口的唯一一个说服力原因
至于其他方面,从设计方面讲,接口的优势大于抽象类
------解决方案--------------------
同意楼上

使用接口

关于设计模式

慢慢学习
------解决方案--------------------
探讨
"接口的优势大于抽象类"??这个不太明白
为何我总是使用抽象类,因为用它来表述一系列类似的类时他们总有那么几个动作是完全一样的,可以被直接提取为超类的动作,于是便用了抽象类。。。问题就出在此

------解决方案--------------------
接口可以说是一个标准,抽象类到子类只能说是功能的进一步加强或更改。如果你要做消息传递的话还是得用接口的吧
------解决方案--------------------
楼主多看看开源的工程(HIBERNATE,STRUTS)


帮助会很大的
------解决方案--------------------
使用抽象类的场景:
有些方法写一次即可,后来的子类中不需要重写
然后在真正用的地方,继承你的子类,就可以使用抽象类中的已实现的方法。

而接口,它的方法在实现类中都需重写,它适用于需要不同实现的时候

将共有的方法在抽象类中实现,方法的实现不一样就声明成abstract,子类再去一一重写。抽象类一般用在工具类之类的
而service层一般用接口

现贴出我们项目里非常好的设计,使用抽象类的代码

Java code

public abstract class AbstBaseQuerySpec implements HibernateCallback,
        Serializable {
    /** 当前页码数 */
    protected Paginate paginate = new Paginate();

    /** 是否需要分页支持 */
    protected boolean paginary = true;

    /**
     * 重置查询条件
     */
    public void resetSpec() {
        paginate.reset();
        reset();
    }
    public Object doInHibernate(Session session) throws HibernateException,
            SQLException {
        return null;
    }
    protected void applyNamedParameterToQuery(Query queryObject,
            String paramName, Object value) throws HibernateException {
        if (value instanceof Collection) {
            queryObject.setParameterList(paramName, (Collection) value);
        } else if (value instanceof Object[]) {
            queryObject.setParameterList(paramName, (Object[]) value);
        } else {
            queryObject.setParameter(paramName, value);
        }
    }

    /**
     * reset spec
     */
    protected abstract void reset();

    /**
     * 执行查询后,通过此方法取得分页信息
     * 
     * @return
     */
    public Paginate getPaginate() {
        return paginate;
    }

    /**
     * @param paginate
     *            The paginate to set.
     */
    public void setPaginate(Paginate paginate) {
        this.paginate = paginate;
    }

    /**
     * @param paginary
     *            The paginary to set.
     */
    public void setPaginary(boolean paginary) {
        this.paginary = paginary;
    }
}


// 基于Hibernate查询规则限定条件
public abstract class AbstQueryStringSpec extends AbstBaseQuerySpec {
    /**   */
    private Map<String, Object> params = new HashMap<String, Object>();

    /**
     * Named hql queryName
     * 
     * @return
     */
    public abstract String queryString();

    /**
     * 
     * @param session
     * @return
     * @throws HibernateException
     * @throws SQLException
     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
     */
    public Object doInHibernate(Session session) throws HibernateException,
            SQLException {
        params.clear();
        Query query = session.createQuery(queryString());
        Iterator<Map.Entry<String, Object>> pIt = params.entrySet().iterator();
        while (pIt.hasNext()) {
            Map.Entry<String, Object> entry = pIt.next();
            applyNamedParameterToQuery(query, entry.getKey(), entry.getValue());
        }
        if (paginary) {
            List total = query.list();
            int totalRows = total.size();
            paginate.setTotalRow(totalRows);
            query.setFirstResult(paginate.getStartIndex());
            query.setMaxResults(paginate.getPageLine());
        }
        List result = query.list();
        return result;
    }

    /**
     * 设置Query接口命名参数
     * 
     * @param name
     * @param value
     */
    protected void setParam(String name, Object value) {
        this.params.put(name, value);
    }
}


/**
 * 功能概述:<br>
 * 机柜统计查询类
 * 
 *  以下是查询类,具体查询数据时
 * 
 */
//public class CabinetStatisticSpec extends AbstQueryStringSpec {
    /** 机房ID */
    private Integer compLocaId;
    @Override
    public String queryString() {
        // hql 查询
        StringBuffer hql = new StringBuffer(
                "select cl.name, "
                        + "sum(case when nc.useHigh=null or nc.useHigh=0 then 1 else 0 end) as unusedCabinet, "
                        + "sum(case when nc.useHigh>0 and nc.useHigh<nc.height then 1 else 0 end) as nofullCabinet, "
                        + "sum(case when nc.useHigh>=nc.height then 1 else 0 end) as fullCabinet, "
                        + "count(*) as totalCabinet "
                        + "FROM NetworkCabinets nc,ComputerLocation cl "
                        + "WHERE nc.compLocaId=cl.id ");

        if (QuerySpecUtil.valid(compLocaId)) {
            hql.append(" AND nc.compLocaId=:compLocaId ");
            this.setParam("compLocaId", compLocaId);
        }
        hql.append(" group by cl.name ");
        return hql.toString();

    @Override
    protected void reset() {
        compLocaId = null;
    }

    public Integer getCompLocaId() {
        return compLocaId;
    }

    public void setCompLocaId(Integer compLocaId) {
        this.compLocaId = compLocaId;
    }

}

spec在struts2 action中作为属性,调用service时作为参数,service中直接用DAO查询,参数就是从action中传过来的spec

我感觉这个设计还是很好的,遂给出部分代码。希望对大家有一点参考作用