链式方法设计

时间:2011-04-25 15:22:14

标签: java oop

我写了一个简单的类来演示链样式方法设计:

public class Cal {

    private Cal(){}

    private boolean isCheckArguments = false;

    public static Cal useAbs() {
        return new Cal(){   
          @Override int check(int i) {
                return Math.abs(i);
            }};
    }

    public static Cal useNormal() {
        return new Cal();
    }   

    public Cal checkArguments() {
        isCheckArguments =true;
        return this;
    }

     int check(int i){ return i;}

     public int plus(int i, int j) {    
        if(isCheckArguments && i<j){
            throw new IllegalArgumentException("i<j!");
        }
        return check(i+j);
    }
}

所以客户端代码可以是:

Cal cal = Cal.useAbs().checkArguments();
int sum = cal.plus(100,2);//IllegalArgumentException occurs

Cal cal2 = Cal.useAbs();
int sum2 = cal.plus(-100,2);//98

Cal cal3 = Cal.useNormal();
int sum3 = cal.plus(-100,2);//-98

我的问题是:这是一个合理的设计吗?比较:int plus(int a, int b, boolean useAbs, boolean checkArguments)。谢谢!

4 个答案:

答案 0 :(得分:5)

听起来你想要一个流畅的界面来构建服务类。番石榴也做类似的事情。你会做这样的事情:

public interface Cal {
   int plus(int a, int b);
}

public class CalBuilder {
    class InternalCal implements Cal {
       boolean useAbs;
       boolean checkArgs;
       public int plus(int a, int b) {
          if(checkArgs) {
             // blah, blah blah
          }
          if(useAbs) {
             // doodle bug, doodle darn
          }
          return a+b; // whatevs
       }
    }
    boolean absSet=false;
    InternalCal holder=new InternalCal();
    public CalBuilder useNormal() {
        if(absSet) { throw new IllegalArgumentException(); } // already called
        holder.useAbs=false;    
        absSet=true;
        return this;
    }

    public CalBuilder useAbs() {
        if(absSet) { throw new IllegalArgumentException(); } // already called
        holder.useAbs=false;    
        absSet=true;
        return this;
    }

    public CalBuilder checkArguments() {
       if(holder.checkArgs) { throw new IllegalArgumentException(); }
       holder.checkArgs=true;
       return this;
    }

    public Cal build() {
       return holder;
    }
}

用法如下:

Cal cal=new CalBuilder().useAbs().checkArguments().build();
int sum=cal.plus(1,2);

答案 1 :(得分:4)

这称为fluent interface,对我来说看起来很合理。

我可能建议更改的一件事是班级名称:Calc显然是一个计算器,而不是Cal(可能是日历而不是计算器)。

答案 2 :(得分:2)

最好的设计是简单的设计。你正在做的是混淆代码。读取和修复错误比“plus(a,b,useAbs,checkArguments)”更难。另外,在useNormal中你返回的是与“new Cal()”相同的对象,因为你覆盖了check(int)方法并用super.check(int)返回父实现

答案 3 :(得分:1)

恕我直言,这种“链接”方法并不是Java中常用的方法,除了构建器或基本上是构建器的东西。

您在这里描述的实际上是计算器构建器。

你应该有一个CalculatorBuilder类,你实例化它,设置多个东西(例如,useAbs,checkArguments等),最后调用“build”。 Build将返回一个计算器,除了用它初始化的状态之外,它不知道它是如何构建的。

此外,我个人并不喜欢混合构建器式逻辑(例如“useAbs”)的设计,以及影响底层对象状态的事物(例如checkArguments)。我会说选一个。生成默认计算器并稍后设置所有内容,或者使用构建器设置所有内容,然后创建无法更改其功能和行为的实例。