第59集:多态特性
学习目标
- 理解多态的概念和作用
- 掌握方法重写实现多态
- 学会使用抽象基类定义接口
- 理解鸭子类型的概念
- 掌握多态在设计中的应用
一、多态概述
1.1 什么是多态
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
1.2 多态的特点
- 方法重写:子类重写父类方法
- 类型兼容:父类引用指向子类对象
- 动态绑定:运行时确定调用哪个方法
二、基本多态示例
2.1 简单的多态示例
class Animal:
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "汪汪叫"
class Cat(Animal):
def make_sound(self):
return "喵喵叫"
def animal_sound(animal):
print(animal.make_sound())
# 多态调用
dog = Dog()
cat = Cat()
animal_sound(dog) # 输出:汪汪叫
animal_sound(cat) # 输出:喵喵叫2.2 多态的好处
# 不使用多态
def dog_sound(dog):
print(dog.make_sound())
def cat_sound(cat):
print(cat.make_sound())
# 使用多态
def animal_sound(animal):
print(animal.make_sound())
# 代码更简洁,扩展性更好三、方法重写与多态
3.1 方法重写实现多态
class Shape:
def draw(self):
print("绘制形状")
def area(self):
return 0
class Rectangle(Shape):
def draw(self):
print("绘制矩形")
def area(self):
return self.width * self.height
class Circle(Shape):
def draw(self):
print("绘制圆形")
def area(self):
return 3.14159 * self.radius ** 2
def process_shape(shape):
shape.draw()
print(f"面积: {shape.area()}")3.2 多态的实际应用
class Payment:
def pay(self, amount):
pass
class CreditCard(Payment):
def pay(self, amount):
print(f"使用信用卡支付: {amount}元")
class WeChatPay(Payment):
def pay(self, amount):
print(f"使用微信支付: {amount}元")
class Alipay(Payment):
def pay(self, amount):
print(f"使用支付宝支付: {amount}元")
def make_payment(payment, amount):
payment.pay(amount)
# 多态调用
payment = CreditCard()
make_payment(payment, 1000)四、抽象基类与多态
4.1 使用抽象基类定义接口
from abc import ABC, abstractmethod
class Database(ABC):
"""数据库抽象基类"""
@abstractmethod
def connect(self):
pass
@abstractmethod
def query(self, sql):
pass
@abstractmethod
def close(self):
pass4.2 实现抽象类
class MySQLDatabase(Database):
def connect(self):
print("连接MySQL数据库")
def query(self, sql):
print(f"执行MySQL查询: {sql}")
def close(self):
print("关闭MySQL连接")
class PostgreSQLDatabase(Database):
def connect(self):
print("连接PostgreSQL数据库")
def query(self, sql):
print(f"执行PostgreSQL查询: {sql}")
def close(self):
print("关闭PostgreSQL连接")4.3 使用多态
def use_database(database):
database.connect()
database.query("SELECT * FROM users")
database.close()
# 可以切换不同的数据库实现
db = MySQLDatabase()
use_database(db)
db = PostgreSQLDatabase()
use_database(db)五、鸭子类型
5.1 什么是鸭子类型
鸭子类型:如果它走起路来像鸭子,叫起来像鸭子,那么它就是鸭子。
5.2 鸭子类型示例
class Duck:
def quack(self):
print("嘎嘎叫")
def walk(self):
print("摇摇摆摆地走")
class Person:
def quack(self):
print("人在学鸭子叫")
def walk(self):
print("人在学鸭子走")
def duck_test(obj):
obj.quack()
obj.walk()
duck = Duck()
person = Person()
duck_test(duck) # 输出:嘎嘎叫、摇摇摆摆地走
duck_test(person) # 输出:人在学鸭子叫、人在学鸭子走5.3 鸭子类型的应用
# 不需要继承,只要实现相同的方法
class FileIterator:
def __init__(self, filename):
self.filename = filename
def __iter__(self):
with open(self.filename, 'r') as f:
for line in f:
yield line.strip()
class ListIterator:
def __init__(self, items):
self.items = items
def __iter__(self):
for item in self.items:
yield item
# 可以统一处理不同的迭代器
def process_items(iterator):
for item in iterator:
print(item)六、多态在集合中的应用
6.1 统一处理不同类型
class Vehicle:
def move(self):
pass
class Car(Vehicle):
def move(self):
print("汽车在公路上行驶")
class Boat(Vehicle):
def move(self):
print("船在水上航行")
class Airplane(Vehicle):
def move(self):
print("飞机在天空中飞行")
# 创建不同类型的交通工具集合
vehicles = [Car(), Boat(), Airplane()]
# 统一处理
for vehicle in vehicles:
vehicle.move()6.2 多态与方法重写
class Employee:
def __init__(self, name):
self.name = name
def calculate_salary(self):
return 0
class FullTimeEmployee(Employee):
def __init__(self, name, base_salary):
super().__init__(name)
self.base_salary = base_salary
def calculate_salary(self):
return self.base_salary
class PartTimeEmployee(Employee):
def __init__(self, name, hourly_rate, hours):
super().__init__(name)
self.hourly_rate = hourly_rate
self.hours = hours
def calculate_salary(self):
return self.hourly_rate * self.hours
class CommissionEmployee(Employee):
def __init__(self, name, base_salary, commission_rate, sales):
super().__init__(name)
self.base_salary = base_salary
self.commission_rate = commission_rate
self.sales = sales
def calculate_salary(self):
return self.base_salary + self.sales * self.commission_rate
# 多态计算薪资
employees = [
FullTimeEmployee("张三", 8000),
PartTimeEmployee("李四", 50, 80),
CommissionEmployee("王五", 5000, 0.1, 20000)
]
for emp in employees:
salary = emp.calculate_salary()
print(f"{emp.name}: {salary}元")七、多态与设计模式
7.1 策略模式
class SortStrategy:
def sort(self, data):
pass
class BubbleSort(SortStrategy):
def sort(self, data):
print("使用冒泡排序")
return sorted(data)
class QuickSort(SortStrategy):
def sort(self, data):
print("使用快速排序")
return sorted(data)
class Sorter:
def __init__(self, strategy):
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def sort(self, data):
return self.strategy.sort(data)
# 使用不同的排序策略
sorter = Sorter(BubbleSort())
data = [5, 2, 8, 1, 9]
result = sorter.sort(data)
sorter.set_strategy(QuickSort())
result = sorter.sort(data)7.2 工厂模式
class ShapeFactory:
@staticmethod
def create_shape(shape_type):
if shape_type == "circle":
return Circle()
elif shape_type == "rectangle":
return Rectangle()
elif shape_type == "triangle":
return Triangle()
else:
raise ValueError("未知的形状类型")
# 使用工厂创建对象
shape1 = ShapeFactory.create_shape("circle")
shape2 = ShapeFactory.create_shape("rectangle")
# 多态调用
shape1.draw()
shape2.draw()八、多态的优势
8.1 代码复用
# 一个函数可以处理多种类型
def process_payment(payment_method, amount):
payment_method.pay(amount)
# 支持多种支付方式
process_payment(CreditCard(), 1000)
process_payment(WeChatPay(), 1000)
process_payment(Alipay(), 1000)8.2 扩展性
# 添加新的支付方式,不需要修改现有代码
class ApplePay(Payment):
def pay(self, amount):
print(f"使用Apple Pay支付: {amount}元")
# 现有代码可以直接使用
process_payment(ApplePay(), 1000)8.3 灵活性
class Logger:
def log(self, message):
pass
class ConsoleLogger(Logger):
def log(self, message):
print(f"[Console] {message}")
class FileLogger(Logger):
def log(self, message):
with open("log.txt", "a") as f:
f.write(f"[File] {message}\n")
class DatabaseLogger(Logger):
def log(self, message):
print(f"[Database] {message}")
# 可以灵活切换日志记录方式
def set_logger(logger):
global current_logger
current_logger = logger
def log_message(message):
current_logger.log(message)九、常见错误与注意事项
9.1 常见错误
- 忘记重写方法:
class Animal:
def make_sound(self):
pass
class Dog(Animal):
# 忘记重写make_sound
pass
dog = Dog()
dog.make_sound() # 不会输出任何内容- 方法签名不一致:
class Parent:
def method(self, a, b):
return a + b
class Child(Parent):
def method(self, a): # 参数不一致
return a * 29.2 注意事项
- 确保子类重写所有抽象方法
- 保持方法签名一致
- 合理使用抽象基类定义接口
- 理解鸭子类型的适用场景
十、课后练习
练习题
编程题
- 定义一个Shape抽象基类
- 创建Rectangle、Circle、Triangle子类
- 实现多态计算面积和周长
编程题
- 定义一个Logger接口
- 实现ConsoleLogger和FileLogger
- 实现日志的切换
思考题
- 多态的好处是什么?
- 什么是鸭子类型?
- 什么时候应该使用抽象基类?
十一、本集总结
核心知识点回顾
- 多态:同一操作作用于不同对象产生不同结果
- 方法重写:子类重写父类方法实现多态
- 抽象基类:定义接口规范
- 鸭子类型:不依赖继承,只依赖方法存在
- 动态绑定:运行时确定调用哪个方法
下集预告
下一集我们将学习类属性与实例属性,深入了解类属性和实例属性的区别与使用。
学习建议: 多态是面向对象编程的核心特性之一,理解多态对于编写灵活、可扩展的代码非常重要。通过实际练习加深理解。