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

解决方案 »

  1.   

    刚刚查了下,接口好于抽象类的优点:
    1.减少继承,降低级联关系
    2.彻底分离动作的定义与实现
    3.支持多重继承(implements other interfaces)
    -------------------------------------------
    那假如所有的实现都有一个同样的动作,也要在每个实现里写一个一模一样的??
    那如果写一个abstract类实现这个interface的那个共性方法,再用一大堆类继承这个abstractClass,那不是更复杂了么??
      

  2.   

    楼主多看看开源的工程(HIBERNATE,STRUTS)
    帮助会很大的
      

  3.   

    问题1:我设计的常用模块(比如控制台打印、字符集转换过滤、格式化日期、日志文件读写、properties文件读写、javaMail、jsonString读取、excel读取、验证码生成)等等模块经常用私有化构造方法+全部静态化方法来设计这些工具类,这样使用起来就是类名+方法名来使用,请问这种设计方法有何利弊?(tij里曾说过:当你的程序充斥着过多的static时,或许你该想想换个设计了,且实际调用起来越看越像面向过程,虽然用起来时确实方便,不用新建实例) 问题3:我为程序中的业务模型层、dao层分别建立了一个工厂,这个工厂以业务模型的名称或代号为参数,以switch\catch的方式去判断并返回所求的实例,但总觉得switch\catch相当臃肿,也觉得,工厂模式除了将对象的创建工作集中到了一处进行统一管理的同时,工厂自己也是够复杂的,尤其是什么工厂方法模式和抽象工厂模式。 
      

  4.   

    问题1:我设计的常用模块(比如控制台打印、字符集转换过滤、格式化日期、日志文件读写、properties文件读写、javaMail、jsonString读取、excel读取、验证码生成)等等模块经常用私有化构造方法+全部静态化方法来设计这些工具类,这样使用起来就是类名+方法名来使用,请问这种设计方法有何利弊?(tij里曾说过:当你的程序充斥着过多的static时,或许你该想想换个设计了,且实际调用起来越看越像面向过程,虽然用起来时确实方便,不用新建实例) 问题3:我为程序中的业务模型层、dao层分别建立了一个工厂,这个工厂以业务模型的名称或代号为参数,以switch\catch的方式去判断并返回所求的实例,但总觉得switch\catch相当臃肿,也觉得,工厂模式除了将对象的创建工作集中到了一处进行统一管理的同时,工厂自己也是够复杂的,尤其是什么工厂方法模式和抽象工厂模式。 ----------------------------------
    100分都没人理了啊?以我的三角等级可再没办法给出更多分了哟
      

  5.   

    使用抽象类的场景:
    有些方法写一次即可,后来的子类中不需要重写
    然后在真正用的地方,继承你的子类,就可以使用抽象类中的已实现的方法。而接口,它的方法在实现类中都需重写,它适用于需要不同实现的时候将共有的方法在抽象类中实现,方法的实现不一样就声明成abstract,子类再去一一重写。抽象类一般用在工具类之类的
    而service层一般用接口现贴出我们项目里非常好的设计,使用抽象类的代码
    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我感觉这个设计还是很好的,遂给出部分代码。希望对大家有一点参考作用
      

  6.   

    问题1:因为你对问题看法是面向过程的,所以你设计类只是为了实现方法。当你以面向对象的观点看待这个世界时,你就会发现..其实这只是两种不同的世界观- -!没有什么所谓的好与不好
    问题2:接口是对象的一个方面的表现,这也是面向对象的观点。举例来说:自行车有可以被骑这个特性,所以设计的时候可以这样public class Bicycle implements Ridable,Ridable这个接口从一个侧面描述了自行车。同样也有别的东西可以被骑,虽然骑法不同...这和抽象类的思想就不一样,估计不会有人设计出这样一个抽象类——可以骑的东西...
    问题3:没看懂你在问什么- -!
    PS:这里能贴UML图么?用语言描述对象是在很累...
      

  7.   

    第一个问题。对于纯粹作为方法集的类,全静态方法很少用(不是不能用,只是太怪异,不符合java的语言习惯),一般来说是用单例模式,这个挺简单的,自己搜一搜去。第二个问题。结合抽象类和接口也可以啊,抽象类首先实现接口,子类再去继承抽象类,OK。第三个问题。你的工厂模式走歪了。一般来说工厂是为了将获得实例的过程与接收对象彻底分离而设立的,同时还兼有隐藏复杂的初始化过程的作用,比如:UserDAO dao = UserDAOFactory.getInstance().createDAO();这里UserDAO很可能只是一个接口,而这个接口的实现是哪个实现类就由工厂决定了,可能是UserOracleDAO,也可能是UserMysqlDAO的实例。
    一般来说是一个类配一个工厂(或者一个抽象类/接口)配一个工厂。你在一个工厂里把该层的所有对象都实例化了,工厂当然会很复杂,你难道要自己写一个Spring的BeanFactory吗?到了Spring,它把所有的工厂都集中起来变成了一个BeanFactory,正像你自己的实现一样,这个工厂也是利用输入一个字串(叫BeanName)来判断你到底是请求哪个类的实例。不同的是,它把每个特定类的细节设置都放到XML配置文件里去了。
      

  8.   

    如果觉得自己的设计思路不行的,建议去学下java设计模式
    下面是我对你的问题的看法
    1: static的类,对象,方法。在你的工程启动的时候他就已经占有了他的内存空间,不管你是否在后面的操作能否有用到。换句话说过多的static类,会加大你的工程启动时的内存占有量。虽然static方法省去了实例的过程以及对象的操作。
    2:接口和抽象类,他们的区别只是定义上,接口算得上是一个特殊化的接口(只是里面的所有方法都是虚的),java语言的特点是,一个类只能继承一个抽象类,实现多个接口。所以有了许许多多的接口,不过你开发久了你马上就会觉得接口的设计方式比抽象类要优雅的多。C++中就没有接口,它可以继承多个抽象类
    3:建议不要自己去写工厂类,因为正常开发人员的水平都是有限的,考虑不足。用spring去控制你的类对象,你写的工厂类只有控制产生而已,类对象诞生之后,你的工厂类就没有去管对象了,而实际上,工厂类应该是管理类对象整个的生命周期,看看spring的Factory
      

  9.   

    我也是新手,我做设计的时候遵循的原则是这样:
    1.所有的实现类都必须实现某一特定接口
    2.为了提高复用程度,用某一抽象类作为support,实现类可以继承此抽象类所以最后的格局是:
    interface MyInterFace{
    }class abstract MySupport implements MyInterFace{
    }calss ImplementClass extends MySupport{
    }这是我看structs2的app example 时发现的感觉很好用,就一直这样用
      

  10.   

    1, 举个例子说 验证码的生成, 如果只有一种生成方法,这种设计 无可厚非,  但是如果存在多种生成办法这样 就不好了,,
    过程式设计会用两个static 函数来表示两种不同的验证码生成方法:public static Code generate1();public static Code generate2();如果是面向对象设计,
    interface CodeGenerate{
      Codge generate();
    }class ConcreteGenerator1 implements CodeGenerate{};
    class ConcreteGenerator2 implements CodeGenerate();
     
    这样设计的好处是可扩展性高,符合 O-C原则2, 接口通常代表一种 职责,或者说某一个方面的功能, 抽象类 经常用于实现一些共有的代码, 面向interface 的编程的好处,同样也是能够做出可扩展性的设计3, factory 就是为了把一类对象的创造放到factory里面,工厂会因为增加新的对象类型而变化, 而且仅此会导致factory变化, 所以一边 factory不应该有太复杂的代码. 我很少看到switch多得很难维护的情况,顶多10几种,如果多了,,那么就要考虑别的设计策略 
      

  11.   

    一、 楼上的有人讲过,Static 的东西是程式一启动就会生成一个实例在内存中,如果静态的东西太多,会占用一些内存资源。除此之外,还有一个问题要注意,静态变量的值问题。三、你的意思是一个工厂,根据一个代号什么的,取出相应的实例。
    这样做是对的,但是看起来很庞大。我想这是因为你的实例化对象的方法的问题,一般工厂都会用反射来实例化对象,所有的实例,都只传入名称及参数就可以了。应该不会用到Switch。
      

  12.   

    接口就是借口吧,未必好哦。推荐使用混入模式,groovy编程。
      

  13.   

    问题1:我设计的常用模块(比如控制台打印、字符集转换过滤、格式化日期、日志文件读写、properties文件读写、javaMail、jsonString读取、excel读取、验证码生成)等等模块经常用私有化构造方法+全部静态化方法来设计这些工具类,这样使用起来就是类名+方法名来使用,请问这种设计方法有何利弊?(tij里曾说过:当你的程序充斥着过多的static时,或许你该想想换个设计了,且实际调用起来越看越像面向过程,虽然用起来时确实方便,不用新建实例)
    部分静态方法还是可以的,比如:格式化日期、properties文件读写,控制台打印,字符集转换过滤等等。
    不过大量使用静态方法确实是设计不够优化的表现,尤其是新手,经常会碰到一段代码不知道怎么才能大家共享调用,于是就静态之。
    这个说到底还是要深入理解OO,理解扩展性、耦合性等非功能因素。
    举例来说:字符集转换,
    你可以写静态方法,Util.convertCharSet(String content,String from,String to);
    也可以:
    CharSetConverter cc=new CharSetConverter(from, to);
    cc.convert(content);
    如果你有大量的字符串需要转换的时候,显然后者的代码更加容易理解,因为不是每次都要带着from,to两个参数,
    你可以说不要这两个参数(从哪种字符集转到另外一种字符集),那你的代码就是固定功能,没有扩展性的。
    总体来讲,如果你确定这些东西都是工具,不涉及业务逻辑,用静态方法,我觉得没什么,方便很重要。
    问题2:我的设计中经常用到抽象类,但却极少用到接口,这正常么?(我的理解是:接口就是抽象类更纯粹的一种表现,但意义是一样的,就是规范了一系列对象的所有动作,使使用这些服务的调用端可以和实际的实现相分离。)
    正是接口的更纯粹抽象使得接口与抽象类不一样,而且,在模块之间,或者你对外提供API的时候,开放接口和开放抽象类是完全不同的。
    作为你的API的使用者,如果你要别人提供的数据继承自你的抽象类,会有很大的制约性(因为人家可能已经继承自他自己的某个类了)。
    所以,面向接口编程,就是为了完全的将合作双方隔离。
    问题3:我为程序中的业务模型层、dao层分别建立了一个工厂,这个工厂以业务模型的名称或代号为参数,以switch\catch的方式去判断并返回所求的实例,但总觉得switch\catch相当臃肿,也觉得,工厂模式除了将对象的创建工作集中到了一处进行统一管理的同时,工厂自己也是够复杂的,尤其是什么工厂方法模式和抽象工厂模式。
    工厂模式,可以使用反射机制来消除if switch。
    当然,前提是你的类命名有一定的规范(与编号之间)。
      

  14.   

    关于抽象类和接口,偶举个例子,门有木门和铁门,这个可以用抽象类和具体类来实现,但是现在要加上报警的功能就要用到接口了, java的jdk设计很多都是这种思想,有空可以看看它的类图