柔性多态:消除多态中父子类的关联性

在说明柔性多态之前先看看下面多态的设计

一般常规的多态程序设计,首先定义多态接口

public interface IShape3 {
    public float getArea();
}

然后在实体类中重写多态函数

public class Circle3 implements IShape3 {
    float r;
    public Circle3(float r){
        this.r = r;
    }
    public float getArea(){
        return r*r*(float)Math.PI;
    }
}
public class Rect3 implements IShape3 {
    private float width,height;
    public Rect3(float width,float height){
        this.width = width;
        this.height = height;
    }
    public float getArea(){
        return width*height;
    }
}

客户端通过动态绑定对接口编程实现了求圆或长方形面积功能。但是考虑一个问题,如果以后需要求图形的周长,那上面这个例子该如何修改?

思路是:重新定义接口IShape3,添加所需要的接口函数(求周长),然后再在继承该接口的对象(Circle3和Rect3)中再实现函数功能。

这样做的后果就是使接口以及实现模块,客户端程序都需要重新修改并且重新编译。但是在实际开发维护中,我们只希望仅仅在底层具体模块功能可以修改并编译,

而接口,上层模块以及客户端程序不需要更改或重新编写。

由此可以看到普通多态的局限性:如果接口函数内容发生变化,那么相应的各实现子类必须发生变化,导致相关联的各级模块必须重新编写和编译。而造成原因莫过于父类与自己的多态函数关联过强。

柔性多态的设计就是正是为了消除这种局限性,下面对上面提到的例子加以“改造”。

定义柔性多态接口

public interface IShape2 {
    public Object dispatch(int nID,Object in);
}

具体实现类

public class Circle2 implements IShape2{
    public float r;
    public Circle2(float r){
        this.r = r;
    }
    public Object dispatch(int nId,Object in){
        Object obj = null;
        switch (nId){
            case 0:
                obj = getArea(in) ;break;
            case 1:
                obj = getPerimeter(in);break;
        }
        return obj;
    }
    Object getArea(Object in){
        float area = (float)Math.PI*r*r;
        return new Float(area);
    }
    Object getPerimeter(Object in){
        float len = (float)Math.PI*r*2.0f;
        return new Float(len);
    }
}

柔性多态的设计思想如下:

1.接口内容固定,如上面IShape2中仅仅定义一个多态接口方法dispatch()

2.子类中重写动态函数dispatch仅仅起到转发作用,且转发的具体函数都不是多态函数。这与第一个例子中多态接口编程思想不一致。

假若现在需要添加新的功能,如求内接三角形的周长。现在只需要在Circle2类中添加一个普通方法getTriLength(),并且在多态函数中添加一个case开关,调用getTriLength()就可以了。

而对接口IShape2根本没有修改。从而削弱了接口类和实现类的强关联,这就是实现柔性多态的关键。

package interfaceAndAbstract.Polymorphism;

/**
 * Created by lenovo on 2017/4/15.
 */
public class Circle2 implements IShape2{
    public float r;
    public Circle2(float r){
        this.r = r;
    }
    public Object dispatch(int nId,Object in){
        Object obj = null;
        switch (nId){
            case 0:
                obj = getArea(in) ;break;
            case 1:
                obj = getPerimeter(in);break;
            case 2:
                obj = getTriLength(in);break;
        }
        return obj;
    }
    Object getArea(Object in){
        float area = (float)Math.PI*r*r;
        return new Float(area);
    }
    Object getPerimeter(Object in){
        float len = (float)Math.PI*r*2.0f;
        return new Float(len);
    }
    Object getTriLength(Object in){
        //具体实现代码
        return null;
    }
}
View Code

下面分析一下dispatch()方法的参数理解

1.上面例子中2个参数,整型的普通功能号nID,输入参数in,类型是Object,相当于泛型编程,使程序更加灵活。

2.改函数的返回值是Object对象,若为null,表明计算失败;若not null,则在强调方用强制类型转换才能得到需要的结果。

测试类

public class Test {
    public static void main(String[] args) {
        IShape2 obj = new Circle2(10.0f);
        Float result = (Float)obj.dispatch(1,null);
        System.out.println("半径10圆形面积:" + result.floatValue());
    }
}

完善:根据nID来获得执行函数并不友好,对于使用者不好去记住每个功能的ID。因此可以在接口中定义一个方法public int query(String strID)

在子类中实现,通过方法名获得nID,再由nID来获得执行函数。

总结:固化父类接口函数定义,子类通过重写多态派发函数,这是柔性多态的基本设计思想。

原文地址:https://www.cnblogs.com/lateink/p/6716377.html