5

当我们有一个纯粹是语义继承而不是行为继承的对象层次结构时,不可避免地我们需要在各处编写“instanceof”或“if/else”来进行运行时类型检查。

例如

如果我有一个对象层次结构

Class Function

Class Average extends Function

Class Sum extends Function

Class Max extends Function

如果在这些类中有一个叫做calculate()的方法,那么我们就没有问题,我们可以利用多态性,这种设计满足LSP。

但是,如果我们出于某种原因不想将此 calculate() 方法添加到此层次结构中,这些对象是纯粹的普通对象,无状态对象仅代表语义。

然后我们被迫到处写下面的代码:

if (function instanceof Average)
//perform average
else if(function instanceof Sum)
//perform sum
else if(function instanceof Max)
//perform max

上面的代码表明了一个糟糕的设计,因为你到处都写了这个代码,这个设计很脆弱,以后很难改变。我想如果数字函数是有限的并且函数的计算在一个地方,这可能取决于复杂性。

到目前为止我所知道的是,要解决上述方法,唯一可能的方法是实现访问者模式,除了使用访问者模式之外,还有其他方法可以解决上述设计吗?

我从访问者模式中看到的一个问题是访问者模式的 accept 方法不返回值,如果 accept() 方法不能完全满足要求,这有时会很不方便。

4

3 回答 3

4

如果您在编译时仍然知道类型,则可以使用辅助类:

class Function {
}

class Average extends Function {
}

class Sum extends Function {
}

class Max extends Function {
}

class FunctionHelper {
  public Number calculate(Average a) {
    return null;
  }

  public Number calculate(Sum s) {
    return null;
  }

  public Number calculate(Max a) {
    return null;
  }

  public Number calculate(Function a) {
    return null;
  }

}

通常,您会将帮助方法设为静态,但您不限于此——您可以使用多种风格的帮助类来做一些相当有趣的事情。

于 2013-05-21T09:12:25.737 回答
1

这些对象是纯粹的普通对象,无状态对象只是代表语义。

听起来您想使用枚举而不是常规对象。

然后您可以使用switch语句并让编译器检查您是否处理了所有情况。

enum Function { Average, Sum, Max }
于 2013-05-21T09:00:03.163 回答
0

我刚刚偶然发现了可能解决您的问题的责任链模式:

为此,我们为每个从公共基类开始的函数创建一个处理程序类

public abstract class FunctionHandler {
    private FunctionHandler nexthandler = null;

    protected abstract boolean isConditionMet(Function function);

    protected abstract void calculate(Function function);

    public void handleFunction(Function function) {
        if(function == null) {
            return;
        }

        if (isConditionMet(function)) {
            calculate(function);
        } else {
            if (nexthandler != null) {
                nexthandler.handleFunction(function);
            }
        }
    }

    public FunctionHandler setNexthandler(FunctionHandler nexthandler) {
        this.nexthandler = nexthandler;
        return nexthandler;
    }
}

接下来我们创建具体的处理程序:

public class Averagehandler extends FunctionHandler {
    @Override
    protected boolean isConditionMet(Function function) {
        return function instanceof Average;
    }

    @Override
    protected void calculate(Function function) {
        // do average stuff
    }
}

public class SumHandler extends FunctionHandler {
    @Override
    protected boolean isConditionMet(Function function) {
        return function instanceof Sum;
    }

    @Override
    protected void calculate(Function function) {
        // do sum stuff
    }
}

public class MaxHandler extends FunctionHandler {
    @Override
    protected boolean isConditionMet(Function function) {
        return function instanceof Max;
    }

    @Override
    protected void calculate(Function function) {
        // do max stuff
    }
}

现在寻找一个很好的中心位置来把你的链放在一起(例如一个实用程序类)

public final class FunctionUtil {
    public static final FunctionHandler HANDLER;

    static {
        HANDLER = new Averagehandler();
        HANDLER.setNexthandler(new SumHandler()).setNexthandler(new MaxHandler());
    }
}

现在你可以开始用调用来替换你的 if-else-blocksFunctionUtil.HANDLER.handleFunction(function);

于 2013-05-31T13:07:02.983 回答