在上一篇,已经讲完了面向对象的三大特征之封装。按照顺序,下面是继承与多态。
啰嗦之前先提一下,继承与多态,与设计模式、设计原则是密不可分的。
继承
继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题。虽然从人类思维来讲,继承一般的逻辑是先有父再有子,但是写的时候可能要稍微有点不同。往往是从子类这一类共同的行为中抽象化出来的父类,也因为父类是抽象出来的不具体,所以有些功能都没办法写,只能写个占位符。实现往往都在子类。
看一个场景,老王要开车到某地。分析下这句话,如果从面向对象的角度想,老王有开车动作,封装成一个类,我们封装成Person类。开车,其中车起到的动作(功能)是运输,往上抽象一下,运输的肯定不止有车,飞机、火车、小单车等交通工具都是运输的,他们的共性就是都是交通工具啊,那么我们抽象化为Vehicle类。
注意下,有很多时候,就在这种写子类写的很多而为了降低耦合让调用方不变的时候,我们就可以通过子类提供共同的行为来抽象化为父类。
class vehicle:
def transport(self,position):
pass
def test(self):
print("父类:测试说明这的确是个交通工具")
class car(vehicle):
def __init__(self):
pass
def transport(self,position):
print("开汽车去",position)
def transport(self,position):
print("开汽车去",position)
class airplane(vehicle):
def __init__(self):
pass
def transport(self,position):
print("坐飞机去",position)
car01 = car()
car01.test()
输出结果:
父类:测试说明这的确是个交通工具
仅仅是说明,子类可以调用父类的方法。
另外,简单提一下Python的内建函数:isinstance()判断实例是不是某个类型、issubclass()判断是不是某个类的子类、如果父类有构造函数则子类必须实现父类的构造函数。
加入我们现在想去某个地方,但是没有说明一定要用什么交通工具,那么,作为调用方怎么调用呢?下面再顶一个Person类:
"""
类:人
动作:出行
"""
class person:
def __init__(self,name):
self.name = name
def goTo(self,vehicle,positon):
vehicle.transport(positon)
"""
类:交通工具
"""
class vehicle:
def transport(self,position):
pass
def test(self):
print("父类:测试说明这的确是个交通工具")
class car(vehicle):
def __init__(self):
pass
def transport(self,position):
print("开汽车去",position)
def transport(self,position):
print("开汽车去",position)
class airplane(vehicle):
def __init__(self):
pass
def transport(self,position):
print("坐飞机去",position)
p0_zhangsan = person("张三")
car01 = car()
p0_zhangsan.goTo(car01,"山东")
airplane01 = airplane()
p0_zhangsan.goTo(airplane01,"日本")
输出结果:
开汽车去 山东
坐飞机去 日本
看到没,作为调用方,Person类中的goto始终不用变,因为调用的是父类vehicle的transport方法,而子类有不同的实现。这就是多态的体现。以不变应万变,无论下面再增加多少交通工具,父类以及调用方的代码不变,这就是开闭原则与依赖倒置原则。
其中父类起到一个隔离的作用,调用者只找父类,而而父类又通过传入子类的不同实现在子类进行真正的业务处理。(感觉就是泛型。。。)
至此,三大特征回忆完了。
最终的目的是为了遵循面向对象思想编程。
其实上面就是设计模式中的桥模式。那个父类就是一个桥。考虑着设计原则以及面向对象封装、继承、多态的思想,成功的透过现象想看本质,化无穷(子类交通工具)为有穷(父类tranport方法不变则调用方永远不变)。