面向对象中父类的确立
保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/29/ )。
封装、继承、多态,这是面向对象的三大特性。这三大特性中,有两个特性都与父类有着深深的关联:
- 继承:是指子类可以获得父类的属性和方法。
- 多态:是指父类引用可以指向父类对象,也可指向子类对象。在调用时,父类的引用可以根据引用具体指向的对象去调用。
可见,父类概念的区分在面向对象的设计中十分基础也十分重要。但实际上,大多数开发者对父类的概念有不小的认知偏差。本文我们将讨论这一点。
传统认知的误区
首先我们给出一个问题。
问题1:矩形是不是正方形的父类?
请先在心中给出这个问题的答案,然后在继续阅读本文。
接下来,我们给出矩形类Rectangle和正方形类Square中的方法(省略方法的具体实现),如下所示。
矩形类:
public class Rectangle {
private double length;
private double width;
private String color;
public Rectangle(double length, double width, String color) {}
public void setLength(double length) {}
public void setWidth(double width) {}
public void setColor(String color) {}
public double getArea() {}
public String getColor() {}
}
正方形类:
public class Square {
private double sideLength;
private String color;
public Square(double sideLength, String color) {}
public void setSideLength(double sideLength) {}
public void setColor(String color) {}
public double getArea() {}
public String getColor() {}
}
然后,请再次回答问题。
问题2:上述所示的矩形是不是正方形的父类?
在问题1中,我们往往认为矩形是正方形的父类,因为,在传统认知(主要是指几何学认知)中,正方形就是矩形的特殊情况,那矩形也必然应该是正方形的父类。
在问题2中,我们查看了矩形类Rectangle和正方形类Square的具体方法后,可以判断出矩形不是正方形的父类,因为后者的很多方式是前者不具备的。这时,如果我让你整理两者的继承关系,大家往往会遵循如下的思路:
- 以矩形类Rectangle作为父类,以正方形类Square作为子类。
- 找出矩形类Rectangle类中子父类共有的方法保留,其他方法则移动到一个新的类中。这个新的类是非正方形的矩形类NotSquare。
- 整理删除各个子类中可以继承得到的方法。
然后会得到下面的类图。
如果这样,那很不幸。你落入了传统认知的误区。
正确的父类确立方法
在面向对象的设计中,父类包含了子类的共有行为,而子类则是在父类基础上的特殊化。在执行这个思想时,我们要摆脱传统认知带来的误导。
假设存在A、B、C、D四个类,我们寻找父类的办法是找寻它们的方法的交集。如果最终的交集恰好等于某个类,则这个类恰好是父类,如左图所示。如果最终的交集小于所有现存的类,则交集方法组成的是父类,如右图所示。
这种父类确立方法摆脱了传统认知带来的误导,能够准确确立父类。这是,我们再分析问题2,便会发现应该是如下所示的类图。
这时我们会发现,矩形类Rectangle和正方形类Square是完全平级的两个子类,而不应该是将矩形类Rectangle作为父类。
不过也要注意,通过交集获取父类是一种遵循面向对象逻辑的方法,最终得到的父类可能在现实中没有对应的事物,进而带来命名上的困难。例如在这里并集区域被命名为了“可着色的区域”ColorableArea。并且,传统的父类确立方法也会面临命名困难,例如在错误的父类划分中也产生了一个难以命名的子类,被命名为了“矩形中不是正方形的部分”NotSquare。
当涉及的类逐渐增加时,这种父类确立方法的优势会更为明显。例如,矩形类、正方形类、圆形类、五边形类都放在一起,按照此方法仍然能够很快的得出各级父类。而如果受到传统认知的误导,则很有可能导致继承关系的杂乱。
可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。