天天看点

Python面对对象:组合的应用

作者:洪较瘦不着调退役it人

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 中选择继承和组合

继承和组合在 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类就实现了这个行为,它充当的不是一个传统你类的作用,理解像是一个辅助类