Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >灵活的设计组合

灵活的设计组合

作者头像
公众号---人生代码
发布于 2020-05-18 08:43:50
发布于 2020-05-18 08:43:50
49400
代码可运行
举报
文章被收录于专栏:人生代码人生代码
运行总次数:0
代码可运行

组合比继承更灵活,因为它可以建模松散耦合的关系。对组件类的更改对复合类影响很小或没有影响。基于组成的设计更适合更改

在本部分中,您将使用合成来实现仍然符合PayrollSystemProductivitySystem要求的更好的设计

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# In productivity.py

class ProductivitySystem:
    def __init__(self):
        self._roles = {
            'manager': ManagerRole,
            'secretary': SecretaryRole,
            'sales': SalesRole,
            'factory': FactoryRole,
        }

    def get_role(self, role_id):
        role_type = self._roles.get(role_id)
        if not role_type:
            raise ValueError('role_id')
        return role_type()

    def track(self, employees, hours):
        print('Tracking Employee Productivity')
        print('==============================')
        for employee in employees:
            employee.work(hours)
        print('')

ProductivitySystem类使用映射到实现角色的角色类的字符串标识符来定义一些角色。它公开一个.get_role()方法,该方法在给定角色标识符的情况下,返回角色类型对象。如果没有找到该角色,则会引发ValueError异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# In productivity.py

class ManagerRole:
    def perform_duties(self, hours):
        return f'screams and yells for {hours} hours.'

class SecretaryRole:
    def perform_duties(self, hours):
        return f'does paperwork for {hours} hours.'

class SalesRole:
    def perform_duties(self, hours):
        return f'expends {hours} hours on the phone.'

class FactoryRole:
    def perform_duties(self, hours):
        return f'manufactures gadgets for {hours} hours.'

您实现的每个角色都公开了一个.perform_duties(),它占用了工作的小时数。这些方法返回一个表示职责的字符串

角色类彼此独立,但它们公开相同的接口,因此它们是可互换的。稍后您将看到如何在应用程序中使用它们

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# In hr.py

class PayrollSystem:
    def __init__(self):
        self._employee_policies = {
            1: SalaryPolicy(3000),
            2: SalaryPolicy(1500),
            3: CommissionPolicy(1000, 100),
            4: HourlyPolicy(15),
            5: HourlyPolicy(9)
        }

    def get_policy(self, employee_id):
        policy = self._employee_policies.get(employee_id)
        if not policy:
            return ValueError(employee_id)
        return policy

    def calculate_payroll(self, employees):
        print('Calculating Payroll')
        print('===================')
        for employee in employees:
            print(f'Payroll for: {employee.id} - {employee.name}')
            print(f'- Check amount: {employee.calculate_payroll()}')
            if employee.address:
                print('- Sent to:')
                print(employee.address)
            print('')

PayrollSystem为每个员工保留一个工资政策的内部数据库。它公开一个.get_policy(),给定一个员工id,返回其工资单策略。如果系统中不存在指定的id,则该方法将引发ValueError异常

calculate_payroll()的实现与以前的工作方式相同。它获取一个雇员列表,计算工资单,并打印结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# In hr.py

class PayrollPolicy:
    def __init__(self):
        self.hours_worked = 0

    def track_work(self, hours):
        self.hours_worked += hours

class SalaryPolicy(PayrollPolicy):
    def __init__(self, weekly_salary):
        super().__init__()
        self.weekly_salary = weekly_salary

    def calculate_payroll(self):
        return self.weekly_salary

class HourlyPolicy(PayrollPolicy):
    def __init__(self, hour_rate):
        super().__init__()
        self.hour_rate = hour_rate

    def calculate_payroll(self):
        return self.hours_worked * self.hour_rate

class CommissionPolicy(SalaryPolicy):
    def __init__(self, weekly_salary, commission_per_sale):
        super().__init__(weekly_salary)
        self.commission_per_sale = commission_per_sale

    @property
    def commission(self):
        sales = self.hours_worked / 5
        return sales * self.commission_per_sale

    def calculate_payroll(self):
        fixed = super().calculate_payroll()
        return fixed + self.commission

首先,您要实现一个PayrollPolicy类,该类充当所有薪资策略的基类。此类跟踪工作小时数,这是所有工资单政策所共有的

其他策略类源自PayrollPolicy。我们在这里使用继承是因为我们想利用PayrollPolicy的实现。此外,SalaryPolicyHourlyPolicyCommissionPolicy也是PayrollPolicy

SalaryPolicy使用weekly_salary值初始化,然后在.calculate_payroll()中使用该值。HourlyPolicy使用hour_rate初始化,并通过利用基本类hours_working实现.calculate_payroll()

CommissionPolicy类派生自SalaryPolicy,因为它希望继承其实现。它是用weekly_salary参数初始化的,但是它还需要一个common_per_sale参数

使用common_per_sale来计算.commission,它被实现为一个属性,因此在请求时计算它。在这个例子中,我们假设每5小时工作一次,而.commission是销售的数量乘以commission_per_sale

首先利用SalaryPolicy中的实现,然后添加计算佣金,从而实现.calculate_payroll()方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# In contacts.py

class AddressBook:
    def __init__(self):
        self._employee_addresses = {
            1: Address('121 Admin Rd.', 'Concord', 'NH', '03301'),
            2: Address('67 Paperwork Ave', 'Manchester', 'NH', '03101'),
            3: Address('15 Rose St', 'Concord', 'NH', '03301', 'Apt. B-1'),
            4: Address('39 Sole St.', 'Concord', 'NH', '03301'),
            5: Address('99 Mountain Rd.', 'Concord', 'NH', '03301'),
        }

    def get_employee_address(self, employee_id):
        address = self._employee_addresses.get(employee_id)
        if not address:
            raise ValueError(employee_id)
        return address

AddressBook类为每个员工保留一个Address对象的内部数据库。它公开一个get_employee_address()方法,该方法返回指定员工id的地址。如果员工id不存在,则会引发一个ValueError错误

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# In contacts.py

class Address:
    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)

该类管理地址组件并提供地址的漂亮表示形式

到目前为止,已经扩展了新类以支持更多功能,但是对以前的设计没有重大更改。这将随着员工模块及其类的设计而改变

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一起来探讨 python 类爆炸问题
由于您不必从特定的类派生对象就可以被程序重用,因此您可能会问为什么应该使用继承而不是仅实现所需的接口。以下规则可能对您有帮助
公众号---人生代码
2020/05/17
6670
Agent配置最佳实践:Prompt工程与参数调优
Hello,我是摘星!🌈 在彩虹般绚烂的技术栈中,我是那个永不停歇的色彩收集者。🦋 每一个优化都是我培育的花朵,每一个特性都是我放飞的蝴蝶。🔬 每一次代码审查都是我的显微镜观察,每一次重构都是我的化学实验。🎵 在编程的交响乐中,我既是指挥家也是演奏者。让我们一起,在技术的音乐厅里,奏响属于程序员的华美乐章。
摘星.
2025/08/08
970
Agent配置最佳实践:Prompt工程与参数调优
如何开发一套考勤管理系统?(附架构图+流程图+代码参考)
在现代企业管理中,考勤管理是至关重要的组成部分。一个高效的考勤管理系统,不仅能帮助企业提升工作效率,还能确保人员出勤的准确性,进而减少人为错误和纠纷。随着科技的发展,传统的纸质考勤方式已经逐渐被自动化和数字化的考勤系统所替代。那么,如何搭建一套高效的考勤管理系统呢?本文将带你深入探讨如何设计、开发一套考勤管理系统,涵盖考勤/外勤打卡、补卡申请、请假/加班申请、调休/出差申请、考勤确认等模块,帮助企业实现更精细化的员工管理。
用户5667915
2025/08/07
1350
如何开发一套考勤管理系统?(附架构图+流程图+代码参考)
将特性与Mixin类混合
python中多重继承的用途之一是通过mixins扩展类功能。mixin是提供其他类方法的类,但不被视为基类
公众号---人生代码
2020/05/19
6870
python 实现多继承
python是少数支持多重继承的现代编程语言之一。多重继承是同时从多个基类派生一个类的能力
公众号---人生代码
2020/05/18
7980
如何开发ERP系统中的生产管理板块(附架构图+流程图+代码参考)
如何高效地整合各项资源、优化生产流程以及及时获得生产数据,已成为提升企业竞争力的关键因素。而ERP(企业资源计划)系统作为企业管理的核心平台,其在生产管理方面的作用愈加凸显。通过对生产管理板块的优化,企业不仅能提升生产效率,减少生产成本,还能更好地掌控生产进度、物料消耗和质量管控。
用户5667915
2025/07/11
1450
如何开发ERP系统中的生产管理板块(附架构图+流程图+代码参考)
连载 Python OOP指南(1)
继承和组合是面向对象的程序设计中的两个主要概念,它们为两个类之间的关系建模。它们驱动应用程序的设计,并确定随着添加新功能或需求变更,应用程序应如何发展。
公众号---人生代码
2020/05/16
9300
使用组合自定义行为
如果您的设计依赖于继承,则需要找到一种方法来更改对象的类型以更改其行为。对于组合,您只需要更改对象使用的策略
公众号---人生代码
2020/05/18
5100
网络工程师学Python-13-继承
在 Python 中,继承是一种重要的面向对象编程概念。通过继承,我们可以定义一个新的类,它继承了现有类的属性和方法。这种代码重用可以使我们更高效地编写程序,并提高代码的可读性和可维护性。
网络技术联盟站
2023/04/20
2130
网络工程师学Python-13-继承
python 中的 组合
组合是一个面向对象的设计概念,模型a是有关系的。在composition中,一个称为composite的类包含另一个称为component的类的对象。换句话说,一个复合类有另一个类的组件
公众号---人生代码
2020/05/18
9280
Java - Jackson JSON Java Parser API
Jackson JSON Java Parser非常流行,并且也用于Spring框架。
小小工匠
2021/08/17
1K0
Python升级之路( Lv7 ) 面向对象深入
第一章 Python 入门 第二章 Python基本概念 第三章 序列 第四章 控制语句 第五章 函数 第六章 面向对象基础 第七章 面向对象深入
时间静止不是简史
2022/06/15
5270
Python升级之路( Lv7 ) 面向对象深入
Cozmo人工智能机器人SDK使用笔记(2)-显示部分face
这篇博文针对SDK教程中的第二部分cozmo_face进行简单介绍,如下: face是cozmo显示的核心部分: 来学习一下,如何操作吧~ 分为3个文件,如上图所示。 1. face image co
zhangrelay
2019/01/28
7110
【Pthon100天学习笔记】Day19 面向对象基础
月薪结算系统 - 部门经理每月15000 程序员每小时200 销售员1800底薪加销售额5%提成
天道Vax的时间宝藏
2021/12/07
3800
Python学习笔记整理(十六) 类的设计
如何使用类来对有用的对象进行建模? 一、Python和OOP Python和OOP实现可以概括为三个概念。 继承     继承是基于Python中属性查找(在X.name表达式中) 多态     在X.method方法中,method的意义取决于X的类型(类) 封装     方法和运算符实现行为,数据隐藏默认是一种惯例。 封装指的是在Python中打包,也就是把实现的细节隐藏在对象接口之后。这并不代表有强制的私有性。封装可以让对象接口的现实 出现变动时,不影响这个对象的用户。 1、不要通过调用标记进行重载 不要在同一个类中对同一个方法名定义两次,后面的会覆盖前面,也不要对对象类型进行测试。应该把程序代码写成预期的对象接口。而不是特定类型的数据类型。 2、类作为记录 通过类的实例来创建多个记录。 3、类和继承:是“一个”关系 (is a) 从程序员的角度来看,继承是由属性点号运算启动的,由此触发实例,类以及任何超类中变量名搜索。 从设计师的角度看,继承是一种定义集合成员关系的方式:类定义了一组内容属性,可由更具体的集合(子类)继承和定制。 子类和超类的继承是1对1的关系. PizzaRobot是一种Chef,Chef是一种Employee.以OOP术语来看,我们称这些关系为“是一个连接”(is a):机器人是个主厨,主厨是一个员工。 class Employee:         def __init__(self,name,salary=0):                 self.name=name                 self.salary=salary         def giveRaise(self,percent):                 self.salary=self.salary+(self.salary*percent)         def work(self):                 print self.name,"does stuff"         def __repr__(self):                 return "<Employee:name=%s,salary=%s>" % (self.name,self.salary) class Chef(Employee):         def __init__(self,name):                 Employee.__init__(self,name,5000)         def work(self):                 print self.name,"make food" class Server(Employee):         def __init__(self,name):                 Employee.__init__(self,name,40000)         def work(self):                 print self.name,"interface with customer" class PizzaRobot(Chef):            def __init__(self,name):#有点想不明白,既然继承就够了,为什么还要在这里构造                 Chef.__init__(self,name)    #Chef.__init__(self,name) =》Employee.__init__(self,name,5000)=>__init__(self,name,salary=0)         def work(self):                 print self.name,"make pizza" if __name__=='__main__':         bob=PizzaRobot('bob')         print bob         bob.work()         bob.giveRaise(0.20)         print bob;print # python employees.py   <Employee:name=bob,salary=5000> bob make pizza <Employee:name=bob,salary=6000.0> 理解有问题的地方 class PizzaRobot(Chef):            def __init__(self,name):#有点想不明白,既然继承就够了,为什么还要在这里构造,下面拿掉这里做对比   
py3study
2020/01/09
7800
Python学习笔记(2)比特操作、类、
比特操作 注意一: 适用范围 Note that you can only do bitwise operations on an integer. Trying to do them on strings or floats will result in nonsensical output!
py3study
2020/01/09
9310
Python从0到100(十八):面向对象编程应用
面向对象编程是一种常见的编程范式,它将现实世界中的实体抽象为对象,通过对象之间的交互来设计和构建软件系统,核心概念包括类、对象、继承、封装和多态。
是Dream呀
2024/05/08
1670
再再肝3天,整理了70个Python面向对象编程案例
Python 作为一门面向对象编程语言,常用的面向对象知识怎么能不清楚呢,今天就来分享一波
周萝卜
2021/11/24
7860
Python编程思想(27):类的继承
继承是面向对象的3大特征之一(另两个特性是封装和组合),也是实现软件复用的重要手段。Python的继承是多继承机制,也就是一个子类可以同时有多个直接父类。
蒙娜丽宁
2020/07/02
1.4K0
数据库期末大作业之职员管理系统(C++语言)
数据库原理与应用实验大作业使学生通过对数据库基础知识的学习,掌握数据库基本操作,使学生掌握应用数据库所必须的所有核心概念和内容,在这个过程中激发学生学习的兴趣,并为后续的专业课程的学习打下坚实的基础。在课内,给学生布置一个数据库设计应用的任务。学生在教师的指导下,以任务驱动方式使学生们熟练掌握数据库的基本应用。
猫咪-9527
2025/06/11
2050
数据库期末大作业之职员管理系统(C++语言)
推荐阅读
相关推荐
一起来探讨 python 类爆炸问题
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档