重载、继承(及多态)

来源:互联网 发布:软件测试 课程介绍 编辑:程序博客网 时间:2024/06/15 15:59
作者:柯伟辰
链接:https://www.zhihu.com/question/52767718/answer/143989505
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

引用@invalid s

在这个问题
面向对象编程的弊端是什么? - 计算机科学 - 知乎
下面的一段回答:

封装:封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫接口

有了封装,就可以明确区分内外,使得类实现者可以修改封装的东西而不影响部调用者;而外部调用者也可以知道自己不可以碰哪里。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

继承+多态:继承和多态必须一起说。一旦割裂,就说明理解上已经误入歧途了。

先说继承:继承同时具有两种含义:其一是继承基类的方法,并做出自己的改变和/或扩展——号称解决了代码重用问题;其二是声明某个子类兼容于某基类(或者说,接口上完全兼容于基类),外部调用者可无需关注其差别(内部机制会自动把请求派发[dispatch]到合适的逻辑)。

再说多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。

很显然,多态实际上是依附于继承的两种含义的:“改变”和“扩展”本身就意味着必须有机制去自动选用你改变/扩展过的版本,故无多态,则两种含义就不可能实现。

所以,多态实质上是继承的实现细节;那么让多态与封装、继承这两个概念并列,显然是不符合逻辑的。不假思索的就把它们当作可并列概念使用的人,显然是从一开始就被误导了——正是这种误导,使得大多数人把注意力过多集中在多态这个战术层面的问题上,甚至达到近乎恶意利用的程度;同时却忽略了战略层面的问题,这就致使软件很容易被他们设计成一滩稀屎(后面会详细谈论这个)。

先说封装,封装的目的就是“互不影响”,模块的设计者可以随便修改模块里面的实现而不影响调用者,调用者也能知道自己能碰哪些东西,只要遵守这个协议,自己的代码就不会因为模块内部的实现变化而跟着完蛋。题主说“封装就是模板设计出来就是固定死的,不能改变,弄成三角形不行,你把中国人民银行印在右上角不行,印上美国人民银行也不行,印上你爸头像更不行。”说对了一部分,还有另一个部分是,假如有一天印钱的人真打算把“中国人民银行”改成“美国人民银行”了,也不会影响用它的人。

再说继承和多态,就像上面引用内容所说的,我在任何时候都反对把这两个概念拆开来看,这两个事情合起来才是和“封装”等价的。一般来讲,我们用继承和多态,只有在你希望某一个函数的行为不同的时候才需要。像5元,10元,20元RMB这个例子的话,只要你在成员里面搞一个value就好了,所以严格来说不能算是多态。除非这些纸币对于一个同样的方法各自独特的行为(即虚函数的作用),那么多态才是有价值的。

如果真写成代码,可能是这样的:

abstract class Money{    private final string bankName = "中国人民银行";    public string getBankName(){return bankName;}         public abstract int value();} class NoteFiveYuan extends Money{    public int value(){return 5;}}class NoteTenYuen extends Money{    public int value(){return 10;}}static int main(){    ArrayList<Money> wallet = new ArrayList<>();    wallet.Add(new NoteFiveYuan());    wallet.Add(new NoteTenYuan());    for(Money money : wallet)    {        println(money.getBankName());        println(money.value());    }}

如果Money的设计者把“中国人民银行”改成了“美国人民银行”,你会发现其他地方完全不需要修改,这就是封装的好处;尤其是如果getBankName里面有一些复杂操作的话,好处会更明显。

如果没有继承和多态,你就做不到把两个类的实例全扔到同一个wallet里面,并且在面对每一个Money的时候,你还必须得去手动判断他到底是哪种Money。现在有了继承和多态,只要你采用覆盖虚函数的方法,根本不用操心。更关键的是,如果以后还有30元的货币类,只要也继承Money并重写value,那么主函数里面数钱的那一段根本就不用动。

原创粉丝点击