Employee包含 address,payroll两个属性
这样员工类与直接的地址、薪资支付方式有了一个松散的关系
payroll中包含工作方式track_work和支付薪资方式calculate_payroll
它们都是直接通过 payroll对象来计算。
class Employee:
def __init__(self, id, name, address, role, payroll):
self.id = id
self.name = name
self.address = address
self.role = role
self.payroll = payroll
def work(self, hours):
duties = self.role.perform_duties(hours)
print(f'Employee {self.id} - {self.name}:')
print(f'- {duties}')
print('')
self.payroll.track_work(hours)
def calculate_payroll(self):
return self.payroll.calculate_payroll()
使用组合自定义对象行为
如果设计依赖于继承,则需要找到一种方法来更改对象的类型以更改其行为。使用组合时,只需更改对象使用的策略即可。
想象一下,我们突然变成了一个按小时计薪的临时雇员。可以在程序执行期间按以下方式修改对象
在 Python 中选择继承和组合
继承和组合在 Python 中是两个不同的面向对象的形式,至于实际的过程 中要选择什么策略云设计要根据具体情况来分析。。
继承到模型“Is A”关系
继承应该只用于对关系进行建模。里氏替换原理说,继承自 的类型对象可以在不改变程序的理想属性的情况下替换类型的对象。
Liskov 替代原则是确定继承是否满足设计方案的最重要准则。
假设您有一个类,该类提供了要在另一个类中重用的实现和接口。最初的想法是,从接口和派生并继承。
一个具体的例子 矩形 Rectangle它有一个面积计算方法area
class Rectangle:
def __init__(self, length, height):
self._length = length
self._height = height
@property
def area(self):
return self._length * self._height
这里有一个子类正方形长与宽是相等的
class Square(Rectangle):
def __init__(self, side_size):
super().__init__(side_size, side_size)
于是测试一下
rectangle = Rectangle(2, 4)
assert rectangle.area == 8
square = Square(2)
assert square.area == 4
print('OK!')
继续修改矩形对象resize方法重新设置长宽的属性
class Rectangle:
def __init__(self, length, height):
self._length = length
self._height = height
@property
def area(self):
return self._length * self._height
def resize(self, new_length, new_height):
self._length = new_length
self._height = new_height
rectangle.resize(3, 5)
assert rectangle.area == 15
print('OK!')
使用 Mixin 类混合功能
Python 中多重继承的用途之一是通过 mixin 扩展类特征。mixin 是一个为其他类提供方法但不被视为基类的类。
mixin 允许其他类重用其接口和实现,而不会成为超类。它们实现一种独特的行为,该行为可以聚合到其他不相关的类。它们类似于构图,但它们创造了更牢固的关系。
将应用程序中某些类型的对象转换为对象的字典表示形式。可以在要支持此功能的每个类中提供一种方法,但其实现似乎非常相似。.to_dict().to_dict()
class Employee:
def __init__(self, id, name, address, role, payroll):
self.id = id
self.name = name
self.address = address
self._role = role
self._payroll = payroll
def work(self, hours):
duties = self._role.perform_duties(hours)
print(f'Employee {self.id} - {self.name}:')
print(f'- {duties}')
print('')
self._payroll.track_work(hours)
def calculate_payroll(self):
return self._payroll.calculate_payroll()
self._role = role
self._payroll = payroll
_role和_payroll对象为私有了。
接着Mixin类来AsDictionaryMixin实现对_属性的特殊操作
class AsDictionaryMixin:
def to_dict(self):
return {
prop: self._represent(value)
for prop, value in self.__dict__.items()
if not self._is_internal(prop)
}
def _represent(self, value):
if isinstance(value, object):
if hasattr(value, 'to_dict'):
return value.to_dict()
else:
return str(value)
else:
return value
def _is_internal(self, prop):
return prop.startswith('_')
class Employee(AsDictionaryMixin):
def __init__(self, id, name, address, role, payroll):
self.id = id
self.name = name
self.address = address
self._role = role
self._payroll = payroll
def work(self, hours):
duties = self._role.perform_duties(hours)
print(f'Employee {self.id} - {self.name}:')
print(f'- {duties}')
print('')
self._payroll.track_work(hours)
def calculate_payroll(self):
return self._payroll.calculate_payroll()
class Address(AsDictionaryMixin):
def __init__(self, street, city, state, zipcode, street2=''):
self.street = street
self.street2 = street2
self.city = city
self.state = state
self.zipcode = zipcode
def __str__(self):
lines = [self.street]
if self.street2:
lines.append(self.street2)
lines.append(f'{self.city}, {self.state} {self.zipcode}')
return '\n'.join(lines)
那么mix类的作用究竟是什么呢?
import json
from employees import EmployeeDatabase
def print_dict(d):
print(json.dumps(d, indent=2))
for employee in EmployeeDatabase().employees:
print_dict(employee.to_dict())
当我们要把一对象转换成json或者dict时mix类就实现了这个行为,它充当的不是一个传统你类的作用,理解像是一个辅助类