16. 应用案例:工资结算系统
某公司有三种类型的员工:部门经理月薪固定 15000 元;程序员按工作时间支付月薪,每小时 200 元;销售员月薪由 1800 元底薪加上销售额 5% 的提成构成。设计一个工资结算系统。
定义抽象类 Employee
部门经理、程序员、销售员都是员工,有相同的属性和行为。我们先设计一个名为 Employee 的父类,再通过继承派生子类。由于不会直接创建 Employee 类的对象,我们可以将其设计成专门用于继承的抽象类。通过 abc 模块中名为 ABCMeta 的元类来定义抽象类。
python
from abc import ABCMeta, abstractmethod
class Employee(metaclass=ABCMeta):
"""员工"""
def __init__(self, name):
self.name = name
@abstractmethod
def get_salary(self):
"""结算月薪"""
pass
使用 @abstractmethod 装饰器将 get_salary 声明为抽象方法:抽象方法就是只有声明没有实现的方法,声明这个方法是为了让子类去重写这个方法。
派生三个子类
python
class Manager(Employee):
"""部门经理"""
def get_salary(self):
return 15000.0
class Programmer(Employee):
"""程序员"""
def __init__(self, name, working_hour=0):
super().__init__(name)
self.working_hour = working_hour
def get_salary(self):
return 200 * self.working_hour
class Salesman(Employee):
"""销售员"""
def __init__(self, name, sales=0):
super().__init__(name)
self.sales = sales
def get_salary(self):
return 1800 + self.sales * 0.05
三个类分别重写了 get_salary 方法,各实现不同——这就是多态:调用相同的方法,不同的子类对象做不同的事情。
使用 isinstance 判断类型并结算
python
emps = [Manager('刘备'), Programmer('诸葛亮'), Manager('曹操'),
Programmer('荀彧'), Salesman('张辽')]
for emp in emps:
if isinstance(emp, Programmer):
emp.working_hour = int(input(f'请输入{emp.name}本月工作时间: '))
elif isinstance(emp, Salesman):
emp.sales = float(input(f'请输入{emp.name}本月销售额: '))
print(f'{emp.name}本月工资为: ¥{emp.get_salary():.2f}元')
isinstance 函数可以判断出一个对象是不是某个继承结构下的子类型,比 type 函数更强大(type 是精准匹配,isinstance 是模糊匹配)。
本章小结
面向对象编程是一种非常流行的编程范式,除此之外还有指令式编程、函数式编程等。由于现实世界是由对象构成的,而对象是可以接收消息的实体,所以面向对象编程更符合人类正常的思维习惯。
类是抽象的,对象是具体的,有了类就能创建对象,有了对象就可以接收消息,这就是面向对象编程的基础。定义类的过程是一个抽象的过程:找到对象公共的属性属于数据抽象,找到对象公共的方法属于行为抽象。
面向对象的四大核心概念:抽象、封装、继承、多态。要想灵活运用需要长时间的积累和沉淀,大量的编程练习和阅读优质的代码是最好的方法。