Java高手速成 | 多态性实战
创始人
2024-05-14 10:17:13
0

 多态性(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类似乎是多态的。确实如此,但只是在一定程度上呈多态性。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...