Python - 面向对象编程 - 三大特性之多态
前置知识
封装
- 详解文章:https://www.cnblogs.com/poloyy/p/15203989.html
- 封装根据职责将属性、方法封装到一个抽象的类中
- 定义类的准则-封装
继承
- 详解文章:https://www.cnblogs.com/poloyy/p/15216652.html
- 继承实现代码的重用,相同的代码不需要重复的编写
多态
- 不同的子类对象调用相同的父类方法,产生不同的执行结果
- 以继承和重写父类方法为前提
- 是调用方法的技巧,不会影响到类的内部设计
程序猿和设计师都是人类,他们都重写了父类的 work 方法,但他们都有自己的实现逻辑
多态的栗子一
需求
- 定义 Dog 类封装方法 game,普通狗狗简单玩耍
- 定义 ChaiQuan 继承 Dog,重写 game 方法,柴犬疯疯癫癫的玩耍
- 定义 Person 类,封装一个和狗玩的方法,在方法内部,直接调用狗对象调用玩耍的方法
类图
实际代码
class Dog: def __init__(self, name): self.name = name def game(self): print(f"{self.name} 狗狗在玩耍") class ChaiQuan(Dog): def game(self): print(f"{self.name} 柴犬在疯疯癫癫的玩耍") class Person: def __init__(self, name): self.name = name def gameWithDog(self, dog): print(f"{self.name} 正在和 {dog.name} 愉快的玩耍") # 直接通过狗实例对象调用 game 实例方法,不需要关心是哪种狗 dog.game() chai = ChaiQuan("小柴犬") dog = Dog("旺财") p = Person("小菠萝") p.gameWithDog(chai) p.gameWithDog(dog) # 输出结果 小菠萝 正在和 小柴犬 愉快的玩耍 小柴犬 柴犬在疯疯癫癫的玩耍 小菠萝 正在和 旺财 愉快的玩耍 旺财 狗狗在玩耍
- Person 类中只需要让狗对象调用 game 方法,而不用关心具体是什么狗
- game 方法是在 Dog 父类中定义的
- 在程序执行时,传入不同的狗对象参数,gameWithDog 就会产生不同的执行结果
通过统一函数接口实现多态
class Dog(object): def sound(self): print("汪汪汪.....") class Cat(object): def sound(self): print("喵喵喵.....") def make_sound(animal): # 统一调用接口 # 不管你传进来是什么动物,我都调用sound()方法 animal.sound() dogObj = Dog() catObj = Cat() make_sound(dogObj) make_sound(catObj) # 输出结果 汪汪汪..... 喵喵喵.....
通过抽象类实现多态
需求
- 定义一个 Person 类,可以开车,也可以停车
- 定义一个 Car 类,提供 drive、stop 的方法
- 定义一个 Truck、BaoMa 类,继承 Car 类,重写 drive、stop 方法
类图
实际代码
class Car: def __init__(self, name): self.name = name def drive(self): # 抛出异常是防止通过 Car 直接定义实例对象 # 如果 Car 的实例对象调用此方法会报错,必须由子类重写才正确 raise NotImplementedError("Subclass must implement abstract method") def stop(self): raise NotImplementedError("Subclass must implement abstract method") class Truck(Car): def drive(self): print(f"{self.name} Truck 准备上路了") def stop(self): print(f"{self.name} Truck 准备停车") class BaoMa(Car): def drive(self): print(f"{self.name} BaoMa 要跑到100km/h了") def stop(self): print(f"{self.name} BaoMa 漂移停车") class Person: def __init__(self, name): self.name = name def driveCar(self, car): print(f"{self.name} 准备开车上路了") car.drive() def stopCar(self, car): print(f"{self.name} 准备靠边停车") car.stop() person = Person("小菠萝") truck = Truck("小卡车") baoma = BaoMa("大宝马") person.driveCar(truck) person.stopCar(baoma) # 输出结果 小菠萝 准备开车上路了 小卡车 Truck 准备上路了 小菠萝 准备靠边停车 大宝马 BaoMa 漂移停车
Car 是一个抽象类,并不需要通过它创建实例对象,所以 Car 的实例方法都会抛出异常,由子类继承 Car,然后重写方法才能正常调用