多态本质是将公共不变的流程固化在父类中,然后在不同子类中实现变化的部分,父类最终调用子类覆盖的父类方法来完成操作。
典型的以电商常见的商品优惠活动为例,因为可能有很多种不同的优惠方式比如满金额减,满金额打折,满件数打折等等。
如果完全不用面向对象,当然也可以实现
F(){
...
switch(优惠活动类型){
case 1: //满金额打折
F1();
case 2:
F2();
case 3:
F3();
}
...
}
F1(){
p1()
p2()
//特殊计算方法
p3()
p4()
}
F2(){
p1()
p2()
//特殊计算方法
p3()
p4()
}
这种方式简单直观,但是每次增加一种优惠方式,都需要修改主方法F,并增加一个Fn方法
假如Fn方法比较繁琐,同时又会有大量类似代码,这种方式在可维护性上,就很成问题了。
通过面向对象可以比较好的解决这个问题
//优惠活动的基类
class FBase(){
p1(){}
p2(){}
p3(){}
p4(){}
//主方法
main(){
p1()
p2()
r=f()
if(r)
p3()
else
p4()
}
//可被覆盖的实际计算方法
f(){}
}
class F1 extends FBase(){
@Override
f(){
//计算特有方法
}
}
class F2 extends FBase(){
@Override
f(){
//计算特有方法
}
}
F(){
FBase o;
switch(优惠活动类型){
case 1: //满金额打折
o=new F1();
case 2:
o=new F2();
case 3:
o=new F3();
}
//计算优惠活动
o.main()
}
这样拆分后,以后增加一种优惠活动,只要增加一个子类,如果没有特别的,一般只需要实现独特的f方法即可,
万一某些优惠活动很特殊,那么也可以覆盖p1,p2这类方法,或者干脆覆盖main方法,既可以保证充分复用,更保持了足够的灵活性。
当然主方法F这里根据活动类型生成不同的对象,这里比较别扭,完全可以优化一下。
一种方式是自己通过反射来实现
首先,通过额外的配置,配置每种类型对应的类名,然后通过反射来新建对象
F(){
String classname=Config.get(优惠活动类型)
//这里通过语言的反射机制从类名来建立对象,不具体展开
FBase o=createByClassName(classname)
}
而对于spring4,则提供了更简洁的方式,可以让spring直接将同类型的对象全部以数组方式自动注入
@Service
public class HuoDong {
/** 由spring注入各类活动实现类 */
private Map<Integer, FBase> m;
@Autowired
private void setHuoDong(FBase[] a) {
// 通过spring注入同类型
m = new LinkedHashMap<Integer, FBase>();
for (FBase o : a) {
//这里每个子类要通过覆盖父类的getType方法返回他们能处理的活动类型
m.put(o.getType(), o);
}
}
F(){
...
FBase o;=m.get(活动类型);
o.main();
...
}
}
以后增加一种活动,仅仅需要增加一个子类即可,其他一切,都将自动实现!