Java 如何决定保留哪些条件以及将哪些条件分解为多态性

Java 如何决定保留哪些条件以及将哪些条件分解为多态性,java,oop,Java,Oop,简要参考: 为了澄清我的问题: 互联网上有太多关于使用多态性而不是继承的文章。 如果这是真的,那么“If-else”和“switches”就不应该出现在大多数java代码中 他们这样做的事实意味着: 在某些情况下,条件句不能转化为多态性 使用if-else的每一个代码都有可能被重构,但它们都没有被重构 现在我的问题 上面哪一个选项是正确的 如果选项1为真,那么“如何确定If-else是否可以被多态性替换” 你链接的那篇文章解释得很好 基本上,它的条件依赖于变量的类型,例如如果foo instan

简要参考:

为了澄清我的问题:

互联网上有太多关于使用多态性而不是继承的文章。 如果这是真的,那么“If-else”和“switches”就不应该出现在大多数java代码中

他们这样做的事实意味着:

在某些情况下,条件句不能转化为多态性

使用if-else的每一个代码都有可能被重构,但它们都没有被重构

现在我的问题

上面哪一个选项是正确的

如果选项1为真,那么“如何确定If-else是否可以被多态性替换”


你链接的那篇文章解释得很好

基本上,它的条件依赖于变量的类型,例如如果foo instanceof Bar。。。非常适合转换为多态性,而不是依赖于变量值的普通条件,例如如果foo==42

经验法则:如果您发现自己使用instanceof或与foo.getClass的比较,那么您可能可以使用多态性简化事情,但并不总是这样。否则,您的条件可能很好

请注意,基于类型变量、getType方法或类似方法执行条件逻辑属于同一规则——您基本上只是将手动类型推断替换为Java的内置类型机制

一个很好的例子可能是经典的Square和Circle类,每个类都实现/扩展了一个Shape接口/类。正方形有边长,圆圈有半径

假设您想要每个形状的面积,可以执行以下操作:

interface Shape {

}
class Square implements Shape {
    public float edgeLength;
}
class Circle implements Shape {
    public float radius;
}
...
public static void main (String[] args) {
    Shape shape = new Square(); // or new Circle()
    if (shape instanceof Square) {
        Square square = (Square) shape;
        System.out.println("Area: " + (square.edgeLength * square.edgeLength));
    } else if (shape instanceof Circle) {
        Circle circle = (Circle) shape;
        System.out.println("Area: " + (Math.PI * circle.radius * circle.radius));
    }
}
这里,用多态性替换条件表示实现区域方法:


这个例子突出了另外两个有趣的地方:首先,对基类的强制转换通常也是可能需要对多态性进行重构的信号。其次,请注意第二个示例中改进的封装。

您链接的文章对此进行了很好的解释

基本上,它的条件依赖于变量的类型,例如如果foo instanceof Bar。。。非常适合转换为多态性,而不是依赖于变量值的普通条件,例如如果foo==42

经验法则:如果您发现自己使用instanceof或与foo.getClass的比较,那么您可能可以使用多态性简化事情,但并不总是这样。否则,您的条件可能很好

请注意,基于类型变量、getType方法或类似方法执行条件逻辑属于同一规则——您基本上只是将手动类型推断替换为Java的内置类型机制

一个很好的例子可能是经典的Square和Circle类,每个类都实现/扩展了一个Shape接口/类。正方形有边长,圆圈有半径

假设您想要每个形状的面积,可以执行以下操作:

interface Shape {

}
class Square implements Shape {
    public float edgeLength;
}
class Circle implements Shape {
    public float radius;
}
...
public static void main (String[] args) {
    Shape shape = new Square(); // or new Circle()
    if (shape instanceof Square) {
        Square square = (Square) shape;
        System.out.println("Area: " + (square.edgeLength * square.edgeLength));
    } else if (shape instanceof Circle) {
        Circle circle = (Circle) shape;
        System.out.println("Area: " + (Math.PI * circle.radius * circle.radius));
    }
}
这里,用多态性替换条件表示实现区域方法:


这个例子突出了另外两个有趣的地方:首先,对基类的强制转换通常也是可能需要对多态性进行重构的信号。其次,请注意第二个示例中改进的封装。

其思想是避免使用测试对象类型的条件,例如

public void doThing() {
    if (myObject instanceof ClassA)
        doSomething();
    else if (myObject instanceof ClassB);
        doSomethingElse();
}
我们希望避免此类测试的原因是,它们是我们代码中未来bug的来源。当一个新类被添加到我们的系统中时,所有这样的测试都必须被检查,并且可能会被更改。迟早,我们人类会犯错误,然后我们就会有错误的代码。另外,它使我们的代码更加复杂,通常速度较慢。在这个简单的例子中,这并不明显,但如果我们以不同的方式测试一组类型,它将是

在这种情况下,myObject是ClassA和ClassB都继承的类的实例;让我们称之为父类ClassP。因此,我们可以避免向类p添加一个名为doSomething的方法,如下所示

class ClassP {
    // lots of ClassP code

    public void doSomething() {
        // basic implementation of method
    }
}
让我们假设这段代码对于ClassA很好,所以对于ClassA实例,我们可以只编写代码

myObject.doSomething();
但是对于ClassB,我们需要不同的行为,所以我们编写代码

class ClassB extends ClassP {
    // lots of ClassB code

    public void doSomething() {
        // different implementation of method
    }
}
所以现在我们可以做了

myObject.doSomething();
对于ClassB实例也是如此。我们不再需要这种条件

功能强大的是,这段代码还将处理将来添加到继承层次结构中的新类型,而不做任何更改。所以如果我们现在添加一个类

class ClassC extends ClassP {
    // lots of ClassC code

    public void doSomething() {
        // totally different implementation of method
    }
}
然后

myObject.doSomething();
仍然可以工作,并且在myObject是ClassC实例时调用新类中的方法,甚至不需要重新编译

有几种多态性,参见维基百科:和。正如你在这些页面上看到的,这是一个有争议的领域

我们在这里使用的类型被称为子类型多态性,并且由于它的实现方式也被称为dynami
c绑定。

这样做的目的是避免使用测试对象类型的条件,例如

public void doThing() {
    if (myObject instanceof ClassA)
        doSomething();
    else if (myObject instanceof ClassB);
        doSomethingElse();
}
我们希望避免此类测试的原因是,它们是我们代码中未来bug的来源。当一个新类被添加到我们的系统中时,所有这样的测试都必须被检查,并且可能会被更改。迟早,我们人类会犯错误,然后我们就会有错误的代码。另外,它使我们的代码更加复杂,通常速度较慢。在这个简单的例子中,这并不明显,但如果我们以不同的方式测试一组类型,它将是

在这种情况下,myObject是ClassA和ClassB都继承的类的实例;让我们称之为父类ClassP。因此,我们可以避免向类p添加一个名为doSomething的方法,如下所示

class ClassP {
    // lots of ClassP code

    public void doSomething() {
        // basic implementation of method
    }
}
让我们假设这段代码对于ClassA很好,所以对于ClassA实例,我们可以只编写代码

myObject.doSomething();
但是对于ClassB,我们需要不同的行为,所以我们编写代码

class ClassB extends ClassP {
    // lots of ClassB code

    public void doSomething() {
        // different implementation of method
    }
}
所以现在我们可以做了

myObject.doSomething();
对于ClassB实例也是如此。我们不再需要这种条件

功能强大的是,这段代码还将处理将来添加到继承层次结构中的新类型,而不做任何更改。所以如果我们现在添加一个类

class ClassC extends ClassP {
    // lots of ClassC code

    public void doSomething() {
        // totally different implementation of method
    }
}
然后

myObject.doSomething();
仍然可以工作,并且在myObject是ClassC实例时调用新类中的方法,甚至不需要重新编译

有几种多态性,参见维基百科:和。正如你在这些页面上看到的,这是一个有争议的领域

我们在这里使用的类型被称为子类型多态性,由于它的实现方式也被称为动态绑定

1在某些情况下,条件句不能转化为多态性。 2使用if-else的每一个代码都有可能被重构,但它们没有被重构

上面哪一个选项是正确的

我假设每个条件都可以重构为某种多态解决方案,但必须在某些地方对条件进行评估。它们不会消失

例如,基本上每个开关

可以转化为隐藏几乎所有条件的多态解决方案

private final Map<Integer, Runnable> switchMap = new HashMap<Integer, Runnable>();
{
    switchMap.put(0, new Runnable() {
        public void run() {
            System.out.println("Hello");
        }
    });
    switchMap.put(5, new Runnable() {
        public void run() {
            System.out.println("World");
        }
    });
}
private final Runnable defaultCase = new Runnable() {
    public void run() {
        System.out.println("!");
    }
};

public void doFooPolyMorphed(int foo) {
    Runnable runnable = switchMap.get(foo);
    if (runnable == null)
        runnable = defaultCase;
    runnable.run();
}
这些条件仍然会被求值,只是代码没有显式地求值

1在某些情况下,条件句不能转化为多态性。 2使用if-else的每一个代码都有可能被重构,但它们没有被重构

上面哪一个选项是正确的

我假设每个条件都可以重构为某种多态解决方案,但必须在某些地方对条件进行评估。它们不会消失

例如,基本上每个开关

可以转化为隐藏几乎所有条件的多态解决方案

private final Map<Integer, Runnable> switchMap = new HashMap<Integer, Runnable>();
{
    switchMap.put(0, new Runnable() {
        public void run() {
            System.out.println("Hello");
        }
    });
    switchMap.put(5, new Runnable() {
        public void run() {
            System.out.println("World");
        }
    });
}
private final Runnable defaultCase = new Runnable() {
    public void run() {
        System.out.println("!");
    }
};

public void doFooPolyMorphed(int foo) {
    Runnable runnable = switchMap.get(foo);
    if (runnable == null)
        runnable = defaultCase;
    runnable.run();
}

条件仍然是可计算的,只是代码没有明确地计算。

您的意思是使用多态性而不是继承,还是使用多态性而不是条件?多态性使代码更灵活。但是,如果您知道您的系统只需要处理两种情况,这个或那个,即if或else,则使用条件句。为什么不必要地使代码复杂化?你是说使用多态性而不是继承,还是使用多态性而不是条件?多态性使代码灵活。但是,如果您知道您的系统只需要处理两种情况,这个或那个,即if或else,则使用条件句。为什么不必要地使代码复杂化?