写点什么

Java 高手速成 | 多态性实战

作者:TiAmo
  • 2023-01-20
    甘肃
  • 本文字数:2579 字

    阅读完需:约 8 分钟

Java高手速成 | 多态性实战

多态性(polymorphism)是 OOP 最强大、最有用的特性。截至目前,多态性用到了所讲的所有其他 OOP 概念和特性。在通向精通 Java 语言编程的征程上,多态性是最高级别概念站点。

一个对象具有跟另一不同类的对象一样的行为,或者具有跟另一不同接口的实现一样的行为。具有这样行为的能力被称为多态性(polymorphism)。如果在因特网上搜索“多态性”一词,就会发现它是“以多种不同形式出现的情况”。变态(metamorphosis)是“通过自然或超自然的手段,改变某物或某人的形状或性质,使其变成完全不同的形状或性质。”因此,Java 多态性是对象在不同的条件下表现或展示出完全不同行为的能力,如同经过了一个变态的过程。

下面开始动手实战,直观理解这一概念。这里采用的是对象工厂(object factory)——一种工厂式的特定编程实现手段。对象工厂是“一种方法,返回的是发生了改变了的原型(或类)的对象”。

01、对象工厂

对象工厂背后的理念是创建一个方法,该方法在某些条件下返回某个类型的新对象。举例来说吧。拿 CalcUsingAlg1 和 CalcUsingAlg2 这两个类做示范:

interface CalcSomething{double calculate();}class CalcUsingAlg1 implements CalcSomething{public double calculate(){ return 42.1; }}class CalcUsingAlg2 implements CalcSomething{private int prop1;private double prop2;public CalcUsingAlg2(int prop1, double prop2) {this.prop1 = prop1;this.prop2 = prop2;}public double calculate(){ return prop1 * prop2; }}
复制代码

可以看到,这两个类实现相同的接口 CalcSomething,但使用的算法不同。

现在,假设这样决定:选择所用的算法是在一个属性文件中,那么,就可创建以下对象工厂:

class CalcFactory{public static CalcSomething getCalculator(){String alg = getAlgValueFromPropertyFile();switch(alg){case "1":return new CalcUsingAlg1();case "2":int p1 = getAlg2Prop1FromPropertyFile();double p2 = getAlg2Prop2FromPropertyFile();return new CalcUsingAlg2(p1, p2);default:System.out.println("Unknown value " + alg);return new CalcUsingAlg1();}}}
复制代码

这个工厂根据 getAlgValueFromPropertyFile()方法返回的值,选择要使用哪种算法。

对第二个算法而言,还用到 getAlg2Prop1FromPropertyFile()和 getAlg2Prop2FromPropertyFile()方法来获取算法可以添加新的算法变量,更改算法参数的源代码或算法选择的过程,但客户端不需要更改代码。多态性的威力体现于此。此外,可以使用继承来实现多态行为。思考下面的类:的输入参数。

但这种复杂性对客户是隐藏的。示范如下:

CalcSomething calc = CalcFactory.getCalculator();double result = calc.calculate();
复制代码

可以添加新的算法变量,更改算法参数的源代码或算法选择的过程,但客户端不需要更改代码。多态性的威力体现于此。此外,可以使用继承来实现多态行为。思考下面的类:

class CalcSomething{public double calculate(){ return 42.1; }}class CalcUsingAlg2 extends CalcSomething{private int prop1;private double prop2;public CalcUsingAlg2(int prop1, double prop2) {this.prop1 = prop1;this.prop2 = prop2;}public double calculate(){ return prop1 * prop2; }}
复制代码

那么,这里的工厂会呈现下面的模样:

class CalcFactory{public static CalcSomething getCalculator(){String alg = getAlgValueFromPropertyFile();switch(alg){case "1":return new CalcSomething();case "2":int p1 = getAlg2Prop1FromPropertyFile();double p2 = getAlg2Prop2FromPropertyFile();return new CalcUsingAlg2(p1, p2);default:System.out.println("Unknown value " + alg);return new CalcSomething();}}}
复制代码

但是,客户端代码仍然不变:

CalcSomething calc = CalcFactory.getCalculator();double result = calc.calculate();
复制代码

如果可以选择,有经验的程序员将使用公共接口来实现。

公共接口允许更灵活的设计,因为 Java 的一个类可以实现多个接口,但仅可以扩展(继承)一个类。

02、instanceof 运算符


不幸的是,事情并不总是那么简单。有时,程序员不得不处理由不相关的类组装而成的代码,而这些不相关的类甚至来自不同的框架。这种情况下,使用多态性可能不是一个可选的办法。不过,仍然可以隐藏算法选择的复杂性,甚至使用 instanceof 运算符来模拟多态行为。对象是某个类的实例时,instanceof 运算符返回 true。

假设有两个不相关的类,具体如下:

class CalcUsingAlg1 {public double calculate(CalcInput1 input){return 42. * input.getProp1();}}
class CalcUsingAlg2{public double calculate(CalcInput2 input){return input.getProp2() * input.getProp1();}}
复制代码

每个类都期待输入某类型的对象,具体如下:

class CalcInput1{private int prop1;public CalcInput1(int prop1) { this.prop1 = prop1; }public int getProp1() { return prop1; }}
class CalcInput2{private int prop1;private double prop2;public CalcInput2(int prop1, double prop2) {this.prop1 = prop1;this.prop2 = prop2;}public int getProp1() { return prop1; }public double getProp2() { return prop2; }}
复制代码

假设一下,如果实现的方法接收到这样一个对象:

void calculate(Object input) {double result = Calculator.calculate(input);//other code follows}
复制代码

这里,仍然使用了多态性,因为将输入描述为 Object 类型。能够做到这一点,是因为 Object 类是所有 Java 类的基类。现在,看看 Calculator 类是如何实现的:

class Calculator{public static double calculate(Object input){if(input instanceof CalcInput1){return new CalcUsingAlg1().calculate((CalcInput1)input);} else if (input instanceof CalcInput2){return new CalcUsingAlg2().calculate((CalcInput2)input);} else {throw new RuntimeException("Unknown input type " +input.getClass().getCanonicalName());}}}
复制代码

由上可见,Calculator 类用的是 instanceof 运算符来选择适当的算法。

通过使用 Object 类作为输入类型,Calculator 类也利用了多态性,但是其大部分实现与多态性无关。

然而,从外部看,Calculator 类似乎是多态的。确实如此,但只是在一定程度上呈多态性。

发布于: 刚刚阅读数: 4
用户头像

TiAmo

关注

有能力爱自己,有余力爱别人! 2022-06-16 加入

CSDN全栈领域优质创作者;阿里云创作者社区专家博主、技术博主、星级博主;华为云享专家;

评论

发布
暂无评论
Java高手速成 | 多态性实战_编程语言_TiAmo_InfoQ写作社区