Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么时候;如有其他",/&引用;“的实例”;是不可避免的,除了使用访客模式,我们如何改进设计?_Java_Design Patterns_Instanceof_Visitor Pattern_Liskov Substitution Principle - Fatal编程技术网

Java 什么时候;如有其他",/&引用;“的实例”;是不可避免的,除了使用访客模式,我们如何改进设计?

Java 什么时候;如有其他",/&引用;“的实例”;是不可避免的,除了使用访客模式,我们如何改进设计?,java,design-patterns,instanceof,visitor-pattern,liskov-substitution-principle,Java,Design Patterns,Instanceof,Visitor Pattern,Liskov Substitution Principle,当我们有一个纯粹是语义继承而不是行为继承的对象层次结构时,我们不可避免地需要到处写“instanceof”或“if/else”来进行运行时类型检查 例如 如果我有一个对象层次结构 Class Function Class Average extends Function Class Sum extends Function Class Max extends Function 如果在这些类中有一个名为calculate()的方法,那么我们就没有问题了,我们可以利用多态性,这种设计满足LS

当我们有一个纯粹是语义继承而不是行为继承的对象层次结构时,我们不可避免地需要到处写“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()方法不能完全满足要求,有时这是不方便的

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

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

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

enum Function { Average, Sum, Max }

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

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;
  }

}
通常,您会使helper方法成为静态的,但您并不局限于此-使用多种风格的helper类,您可以做一些相当有趣的事情。

我刚刚偶然发现了一些可能解决您问题的方法:

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

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
    }
}
现在找一个好的中心位置来把你的链条放在一起(例如,一个实用类)


现在,您可以开始用调用
FunctionUtil.handle.handleFunction(函数)替换if-else块

战略模式如何:?不要认为战略会起作用,请检查我下面的评论。但是如果那些if-elseif-else块在您的项目中随处可见,那么将该块重构为一个单独的实用程序方法可能是可行的,所以看起来没有简单的方法来实现更好的设计?如果/否则分支是不可避免的?看起来只要你坚持这样做,除非你能更改你的代码
函数
类在我看来,这并不能解决问题,因为你仍然需要执行切换,而且它是高度不可标度的。@MichalBorek:在函数上没有任何方法,如何避免切换?您还可以向枚举添加
calculate
方法。是的。但OP不需要方法(出于未知原因)。若方法避免了切换(他们应该这样做),那个么就不再需要枚举了。这是一种有点危险的方法,因为它依赖于编译时调度。最后一个方法(带函数)除了要避免的同一个实例之外,还要做什么。@Thilo-我不认为这很危险-我注意到你必须在编译时知道类型。最后一个
函数
实现相当于一个默认值,它可能
返回0。因此这将返回0:
函数x=newsum();计算(x)这将不会:
Sum x=new Sum();计算(x)@Thilo-正确。因此,如果您在编译时仍然知道类型,那么我的评论是……如果您有这种编译时耦合,那么您根本不需要任何标记对象。您可以使用一个方法
calculate\u sum()
和一个方法
calculate\u max()
。我能看到这些函数对象(没有状态或行为)的唯一原因是能够在运行时打开它们。谢谢,宏,但是,我只是看了你的建议,我不太明白为什么我们需要引入责任链来解决这个问题?仅仅使用每个处理程序对象来处理每个函数还不够吗?我在想,如果使用这种方法,一个单一的处理程序就足够了,情况会是这样的。责任链使您不再需要决定哪一个处理程序适合于手头的
函数
对象。它只是获取对象并将其传递给处理程序,除非有人有权处理实际类型的函数
public final class FunctionUtil {
    public static final FunctionHandler HANDLER;

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