为继承与多态而设计

Python 面向对象编程

Alex Yarosh

Content Quality Analyst @ DataCamp

多态

 

 

使用统一接口操作不同类的对象

Python 面向对象编程

账户类层级

Python 面向对象编程

关键在于接口

# Withdraw amount from each of accounts in list_of_accounts
def batch_withdraw(list_of_accounts, amount):
   for acct in list_of_accounts:
      acct.withdraw(amount)

b, c, s = BankAccount(1000), CheckingAccount(2000), SavingsAccount(3000) batch_withdraw([b,c,s]) # <-- Will use BankAccount.withdraw(), # then CheckingAccount.withdraw(), # then SavingsAccount.withdraw()
  • batch_withdraw() 无需检查对象即可知道调用哪个 withdraw()
Python 面向对象编程

里氏替换原则

 

基类应可与其任意子类互换,而不改变程序任何性质

BankAccount 可用处,CheckingAccount 也应可用

Barbara Liskov 的照片

Python 面向对象编程

里氏替换原则

 

基类应可与其任意子类互换,而不改变程序任何性质

语法层面
  • 函数签名兼容
    • 参数、返回值
语义层面
  • 对象与程序状态保持一致
    • 子类方法不强化输入条件
    • 子类方法不削弱输出条件
    • 不新增异常
Python 面向对象编程

违反 LSP 的情形

语法不兼容

BankAccount.withdraw() 需要 1 个参数,但 CheckingAccount.withdraw() 需要 2 个

子类强化了输入条件

BankAccount.withdraw() 接受任意金额,但 CheckingAccount.withdraw() 假定金额受限

子类削弱了输出条件

BankAccount.withdraw() 只能留下正余额或报错,CheckingAccount.withdraw() 可能留下负余额

Python 面向对象编程

违反 LSP 的情形

→ 在子类方法中更改额外属性

→ 在子类方法中抛出额外异常

Python 面向对象编程

 

 

 

 

$$\text{\textbf{\Huge{无 LSP——无继承}}}$$

Python 面向对象编程

¡Vamos a practicar!

Python 面向对象编程

Preparing Video For Download...