Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用组合自定义行为

使用组合自定义行为

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

如果您的设计依赖于继承,则需要找到一种方法来更改对象的类型以更改其行为。对于组合,您只需要更改对象使用的策略

想象一下,我们的经理突然变成了按小时计酬的临时雇员。您可以通过以下方式在程序执行期间修改对象

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

from hr import PayrollSystem, HourlyPolicy
from productivity import ProductivitySystem
from employees import EmployeeDatabase

productivity_system = ProductivitySystem()
payroll_system = PayrollSystem()
employee_database = EmployeeDatabase()
employees = employee_database.employees
manager = employees[0]
manager.payroll = HourlyPolicy(55)

productivity_system.track(employees, 40)
payroll_system.calculate_payroll(employees)

该程序从EmployeeDatabase获取员工列表,并检索第一个员工,即我们想要的经理。然后,它会创建一个新的HourlyPolicy,初始化为每小时$55,并将其分配给manager对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python program.py

Tracking Employee Productivity
==============================
Employee 1 - Mary Poppins:
- screams and yells for 40 hours.

Employee 2 - John Smith:
- does paperwork for 40 hours.

Employee 3 - Kevin Bacon:
- expends 40 hours on the phone.

Employee 4 - Jane Doe:
- manufactures gadgets for 40 hours.

Employee 5 - Robin Williams:
- does paperwork for 40 hours.


Calculating Payroll
===================
Payroll for: 1 - Mary Poppins
- Check amount: 2200
- Sent to:
121 Admin Rd.
Concord, NH 03301

Payroll for: 2 - John Smith
- Check amount: 1500
- Sent to:
67 Paperwork Ave
Manchester, NH 03101

Payroll for: 3 - Kevin Bacon
- Check amount: 1800.0
- Sent to:
15 Rose St
Apt. B-1
Concord, NH 03301

Payroll for: 4 - Jane Doe
- Check amount: 600
- Sent to:
39 Sole St.
Concord, NH 03301

Payroll for: 5 - Robin Williams
- Check amount: 360
- Sent to:
99 Mountain Rd.
Concord, NH 03301

在Python中选择继承和组合

到目前为止,您已经了解了在Python中继承和组合是如何工作的。您已经看到派生类继承了它们的基类的接口和实现。您还看到了组合允许您重用另一个类的实现

对于同一个问题,您已经实现了两个解决方案。第一个解决方案使用多重继承,第二个使用复合

您还看到Python的duck类型化允许您通过实现所需的接口来重用具有程序现有部分的对象。在Python中,没有必要从基类派生出要重用的类

此时,您可能会问什么时候在Python中使用继承与组合。它们都支持代码重用。继承和组合可以解决Python程序中的类似问题

一般的建议是使用在两个类之间创建较少依赖关系的关系。这种关系就是组成。不过,有时继承会更有意义。

以下部分提供了一些指导原则,帮助您在Python中的继承和组合之间做出正确的选择

继承到模型“a”关系

继承仅应用于为一个关系建模。Liskov的替换原理说,继承自Base的Derived类型的对象可以替换Base类型的对象,而无需更改程序的所需属性

Liskov的替代原则是决定继承是否是合适的设计解决方案的最重要的指导原则。不过,答案可能并非在所有情况下都是直截了当的。幸运的是,您可以使用一个简单的测试来确定您的设计是否遵循Liskov的替换原则

假设您有一个类a,它提供了一个您希望在另一个类B中重用的实现和接口。您最初的想法是可以从a派生出B,并继承接口和实现。为了确保这是正确的设计,您需要遵循以下步骤:

您有一个类矩形,它公开一个.area属性。您需要一个类Square,它也有一个.area。似乎正方形是一种特殊类型的矩形,所以您可以从它派生并利用接口和实现。

正方形是长方形,因为它的面积是由它的高乘以它的长计算出来的。约束条件是这个平方。高度和广场。长度必须相等。

它是有意义的。你可以证明这种关系,并解释为什么正方形是长方形。让我们来颠倒一下这种关系,看看它是否有意义

长方形是正方形,因为它的面积是由它的高乘以它的长计算出来的。差值就是这个矩形。高度和矩形。宽度可以独立变化

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

class Rectangle:
    def __init__(self, length, height):
        self._length = length
        self._height = height

    @property
    def area(self):
        return self._length * self._height

使用长度和高度初始化Rectangle类,它提供一个.area属性来返回该区域。长度和高度被封装,以避免直接改变它们。

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

class Square(Rectangle):
    def __init__(self, side_size):
        super().__init__(side_size, side_size)

Square类使用side_size初始化,该side_size用于初始化基类的两个组件。现在,您编写一个小程序来测试行为

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

rectangle = Rectangle(2, 4)
assert rectangle.area == 8

square = Square(2)
assert square.area == 4

print('OK!')

运行程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python rectangle_square_demo.py

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

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

.resize()采用对象的new_lengthnew_width。您可以将以下代码添加到程序中,以验证其是否正常运行

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

rectangle.resize(3, 5)
assert rectangle.area == 15

print('OK!')

您调整矩形对象的大小,并断言新区域正确。您可以运行该程序以验证行为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python rectangle_square_demo.py

OK!

那么,如果调整正方形大小会怎样?修改程序,然后尝试修改正方形对象

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

square.resize(3, 5)
print(f'Square area: {square.area}')

将与矩形相同的参数传递给square.resize(),然后打印该区域。当你运行程序时,你会看到

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python rectangle_square_demo.py

Square area: 15
OK!

程序显示,新的区域是15像矩形对象。现在的问题是,square对象不再满足其长度和高度必须相等的square类约束

你怎么解决这个问题?你可以尝试几种方法,但所有的方法都会很尴尬。您可以在square中覆盖.resize()并忽略height参数,但是这对于查看程序的其他部分的人来说会很混乱,因为这些部分的矩形正在被调整大小,而其中一些矩形并没有得到预期的区域,因为它们实际上是正方形。

在一个像这样的小程序中,可能很容易发现奇怪行为的原因,但是在一个更复杂的程序中,问题就更难找到了

事实是,如果能够以两种方式证明两个类之间的继承关系,就不应该从另一个类派生出另一个类

在本例中,SquareRectangle继承.resize()的接口和实现是没有意义的。这并不意味着方形对象不能调整大小。这意味着接口是不同的,因为它只需要一个side_size参数

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
springboot文件上传及虚拟路径设置
今日主题:springboot文件上传及虚拟路径设置 简介 相信大家在做项目中会遇到一些情况,比如文件上传,但是大家会发现他上次的目录是target目录下,也就是说,只要target目录没了,文件也就没了,这个是我们不想看到的,然后有些人就是直接将文件存到磁盘就好了啊,这个思路是没错的,但是我们在前端却不能直接引用磁盘里的真实路径的文件,因为这个存在安全问题,所以这个时候,我们就要用web服务器来帮我们做一个虚拟映射,我们访问一个虚拟路径,其实访问的就是本机的真实路径,这样保证了安全性。 环境 spri
java后端指南
2021/05/13
2.2K0
springboot文件上传及虚拟路径设置
20181125_ARTS_week22
这个解法来自 https://leetcode.com/problems/maximum-subarray/discuss/139218/Javascript-very-clear-and-short-DP-solution
Bob.Chen
2018/12/17
5080
记一次批量修改文件后缀名的经历
创建一个txt文本,将以上代码复制到文本中,保存修改文本后缀.txt为.bat(如图所示)
菜菜有点菜
2022/03/11
1.5K0
记一次批量修改文件后缀名的经历
python知识点100篇系列(5) -根据后缀名整理文件夹
平常用浏览器在互联网下载的文件,一般都在一个“下载”文件夹内,里面的文件什么格式的都有,看着就很乱;所以看能不能给整理一下,这个活python可以干;
JQ实验室
2024/09/18
2000
OSG加载倾斜摄影数据
ContextCapture(Smart3D)生成的倾斜摄影模型数据一般都形如如下组织结构:
charlee44
2020/05/08
3.4K0
windows下,c /c++实现磁盘扫描,结合配置文件,读取特定后缀文件目录代码
http://download.csdn.net/detail/wangyaninglm/8301303
流川疯
2019/01/18
1.8K0
Python修改文件后缀名[通俗易懂]
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/09
6.4K0
C++ 利用 ifstream 和 ofstream 读取和修改文件内容
C 语言读取文件的时候很麻烦,C++ 相对来说有很方便的库可以用,方便的多,所以平常开发中推荐使用 C++ 中的库去读写文件。本文介绍如何利用 C++ 进行最简单的读写文件操作。
Frank909
2019/03/15
35.7K0
C++资源编译工具,用于将任何格式的文件编译成C++代码
resource_maker.zip          linux自带了一个名叫xxd的工具,带参数-i运行时,效果类似,如:xxd -i /bin/ls。
一见
2018/08/10
1.3K0
Node.js 中使用 ES6 中的 import / export 的方法大全
Node.js 中使用 ES6 中的 import / export 的方法大全
一个会写诗的程序员
2018/12/06
5.4K0
Node.js 中使用 ES6 中的  import / export 的方法大全
如何使用Python去除文件后缀名?
在Python中,我们常常需要操作文件,包括文件的读取、写入、重命名等操作。在文件操作中,我们经常会遇到需要去除文件后缀的问题。那么,Python如何去除文件后缀呢?本文我们将介绍如何使用Python来去除文件后缀。
霍格沃兹测试开发Muller老师
2024/03/15
1.5K0
全网最全upload-labs通关攻略(建议收藏)
Upload-labs是一个帮你总结所有上传漏洞类型的靶场,学习上传漏洞原理,复现上传漏洞必备靶场环境,玩起来吧!项目地址:https://github.com/c0ny1/upload-labs
网络安全自修室
2021/11/25
11.7K0
全网最全upload-labs通关攻略(建议收藏)
C/C++编程: 获取路径里的文件名称、后缀名
windows下使用C/C++编写一个方法,传入文件的完整路径,取出文件的基本名称,后缀名等数据。
DS小龙哥
2022/04/08
2.4K0
C/C++编程: 获取路径里的文件名称、后缀名
c++ 常用的遍历,删除,分割等等文件处理函数代码实现
原文链接:https://www.cnblogs.com/DOMLX/p/9622851.html
徐飞机
2018/09/30
1.1K0
python之tkinter进阶-批量修改文件后缀名
相信大家tkinter的基础已经打好了,那么接下来说一下tkinter关于文件操作的一些内容。大家都在windows操作过选择文件,选择或上传,一般是图片比较多。或下载的时候让你选择文件的路径,接下来就用tkinter实现一下文件选择批量修改文件后缀名。
找Bug
2022/07/22
1.7K0
python之tkinter进阶-批量修改文件后缀名
文件上传靶机实验记录
前端JS后缀名校验,通过审查元素发现onsubmit="return checkFile()”校验函数我们将其删除直接上传(浏览器禁用JS脚本也能上传,BURP抓包更改后缀名也能上传)webshell。
菜菜有点菜
2022/03/18
6.2K0
文件上传靶机实验记录
[C++]使用C++部署yolov10目标检测的tensorrt模型支持图片视频推理windows测试通过
【测试通过环境】 vs2019 cmake==3.24.3 cuda11.7.1+cudnn8.8.0 tensorrt==8.6.1.6 opencv==4.8.0
云未归来
2025/07/21
1000
[C++]使用C++部署yolov10目标检测的tensorrt模型支持图片视频推理windows测试通过
C/C++常见gcc编译链接错误解决方法
用“-Wl,-Bstatic”指定链接静态库,使用“-Wl,-Bdynamic”指定链接共享库,使用示例: -Wl,-Bstatic -lmysqlclient_r -lssl -lcrypto -Wl,-Bdynamic -lrt -Wl,-Bdynamic -pthread -Wl,-Bstatic -lgtest ("-Wl"表示是传递给链接器ld的参数,而不是编译器gcc/g++的参数。) 1) 下面是因为没有指定链接参数-lz(/usr/lib/libz.so,/usr/lib/libz.a ) /usr/local/mysql/lib/mysql/libmysqlclient.a(my_compress.c.o): In function `my_uncompress': /home/software/mysql-5.5.24/mysys/my_compress.c:122: undefined reference to `uncompress' /usr/local/mysql/lib/mysql/libmysqlclient.a(my_compress.c.o): In function `my_compress_alloc': /home/software/mysql-5.5.24/mysys/my_compress.c:71: undefined reference to `compress' 2) 下面是因为没有指定编译链接参数-pthread(注意不仅仅是-lpthraed) /usr/local/mysql/lib/mysql/libmysqlclient.a(charset.c.o): In function `get_charset_name': /home/zhangsan/mysql-5.5.24/mysys/charset.c:533: undefined reference to `pthread_once' 3) 下面这个是因为没有指定链接参数-lrt /usr/local/thirdparty/curl/lib/libcurl.a(libcurl_la-timeval.o): In function `curlx_tvnow': timeval.c:(.text+0xe9): undefined reference to `clock_gettime' 4) 下面这个是因为没有指定链接参数-ldl /usr/local/thirdparty/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup': dso_dlfcn.c:(.text+0x4c): undefined reference to `dlopen' dso_dlfcn.c:(.text+0x62): undefined reference to `dlsym' dso_dlfcn.c:(.text+0x6c): undefined reference to `dlclose' 5) 下面这个是因为指定了链接参数-static,它的存在,要求链接的必须是静态库,而不能是共享库 ld: attempted static link of dynamic object 如果是以-L加-l方式指定,则目录下必须有.a文件存在,否则会报-l的库文件找不到:ld: cannot find -lACE 6) GCC编译遇到如下的错误,可能是因为在编译时没有指定-fPIC,记住:-fPIC即是编译参数,也是链接参数 relocation R_x86_64_32S against `vtable for CMyClass` can not be used when making a shared object 7) 下面的错误表示gcc编译时需要定义宏__STDC_FORMAT_MACROS,并且必须包含头文件inttypes.h test.cpp:35: error: expected `)' before 'PRIu64' 8) 下面是因为在x86机器(32位)上编译没有指定编译参数-march=pentium4 ../../src/common/libmooon.a(logger.o): In function `atomic_dec_and_test': ../../include/mooon/sys/atomic_gcc.h:103: undefined reference to `__sync_sub_and_fetch_4' 9) 下列错误可能是因为多了个“}” error: expected d
一见
2018/08/10
8.1K0
4.5 C++ Boost 文件目录操作库
Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量、可移植、高效的C应用程序。Boost库可以作为标准C库的后备,通常被称为准标准库,是C标准化进程的重要开发引擎之一。使用Boost库可以加速C应用程序的开发过程,提高代码质量和性能,并且可以适用于多种不同的系统平台和编译器。Boost库已被广泛应用于许多不同领域的C++应用程序开发中,如网络应用程序、图像处理、数值计算、多线程应用程序和文件系统处理等。
王瑞MVP
2023/08/21
5890
nodejs实现批量修改文件内容 | 附断更红包
一番之前不是有一个网站吗,efonfihgint.imwork.net。但这是个二级域名,很多时候用起来不方便,自主性还是稍差了一点。
efonfighting
2020/02/21
4.1K0
nodejs实现批量修改文件内容 | 附断更红包
推荐阅读
相关推荐
springboot文件上传及虚拟路径设置
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验