对象的多态性是怎么体现的,与重载有什么不同
\quad
\quad
现在有这样一个需求:
\quad
\quad
要求结合对象的多态性,对一个简易的商场打折系统的代码进行重构:
public static int calculatePrice(String discountStrategy, int price, User user) {
switch (discountStrategy) {
case "NoDiscount":
return price;
case "Discount95":
return (int) (price * 0.95);
case "OnlyVip":
{
if (user.isVip()) {
return (int) (price * 0.95);
} else {
return price;
}
}
default:
throw new IllegalStateException("Should not be here!");
}
}
\quad
\quad
其实题目想表达的意思说直白点就是:当我们将上面的代码写完后,我们会觉得该实现的需求都实现了,很好。但是,当我们需在里面增加一种情况,比如5折时,我们就需要在case中新增一个情况,如果有1000种情况,那么就有1000个case,可读性非常差。那么根据题目的意思,我们需要做的就是把每一种情况,单独放到一个方法中,单独实现。
\quad
\quad
实现思路:
\quad
\quad
1.定义父类方法,可以任意实现一种折扣方法。后面可以根据该父类方法,利用子类对父类方法的重写,在子类中实现其他方法。
\quad
\quad
举例说明:对于意外情况的实现
public class DiscountStrategy {
public int discount(int price, User user) {
throw new UnsupportedOperationException();//异常情况的处理(2019.07.06)
}
}
\quad
\quad
2. 为每种情况建立一个单独的方法,分别返回该种折扣情况下的应付金额。
\quad
\quad
举例说明:对于VIP用户实行95折的情况的实现
public class OnlyVipDiscountStrategy extends DiscountStrategy{
@Override//重写父类的方法
public int discount(int price, User user) {
if (user.isVip()){
price*=0.95;
//由于方法的返回值类型为int,故乘以0.95会损失精确度,这里仅仅作为教学。
}
return price;
}
}
\quad
\quad
3.到这里应该可以发现,在每一种方法中都有price、user这两个参数,每次不同的就是调用的方法不同。那么将方法中的公共部分提取出来,用以提供一个统一的对外接口,让该接口去根据传入该方法的参数选择不同的实现方式。
\quad
\quad
代码如下:
public class PriceCalculator {
public static int calculatePrice(DiscountStrategy strategy, int price, User user){
return strategy.discount(price, user);
}
}
\quad \quad 最后,生成一下test测试,检查代码的实际效果:
package com.github.hcsp.polymorphism;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class PriceCalculatorTest {
@Test
public void test() {
Assertions.assertEquals(
95, PriceCalculator.calculatePrice(new Discount95Strategy(), 100, User.dios("屌丝")));
Assertions.assertEquals(
100,
PriceCalculator.calculatePrice(
new OnlyVipDiscountStrategy(), 100, User.dios("屌丝")));
Assertions.assertEquals(
95,
PriceCalculator.calculatePrice(new OnlyVipDiscountStrategy(), 100, User.vip("土豪")));
Assertions.assertEquals(
100, PriceCalculator.calculatePrice(new NoDiscountStrategy(), 100, User.vip("土豪")));
}
}
\quad \quad 总结:自己在刚开始接触到对象三大特性之一,"多态"时,总是不明白重载与多态的关系,有些地方说重载是多态的体现。在我的理解中,多态就是同一方法对不同参数所执行的不同的操作。比如代码中的方法:
public static int calculatePrice(DiscountStrategy strategy, int price, User user)
当我们调用该方法时,传入的参数为:
PriceCalculator.calculatePrice(new Discount95Strategy(), 100, User.dios("屌丝"))
则调用全场95折的方法。从这个方面讲,多态可以说是同一行为具有多个不同表现形式的能力。这样说可能与重载有些类似,那么重载是如何表现的,举个例子:
public class Test {
public int caculate(int s1,int s2){
return s1*s2;
}
public int caculate(int s1,int s2,int s3){
return s1*s2*s3;
}
public static void main(String[] args) {
Test test=new Test();
System.out.println(test.caculate(1,2));
System.out.println(test.caculate(1,2,3));
}
}
\quad \quad 同一函数名,对不同的参数列表(包括参数的类型不同)所表现出不同的方法。可以看出,上面重载的过程中,没有继承关系的发生,是一个静态的过程,那么是不是可以说重载的过程是一种静态的多态,可以参考百度百科的说法:https://baike.baidu.com/item/重载。