最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Python3萌新入门笔记(29)

Python教程 小楼一夜听春语 5972浏览 0评论

这一篇内容,我们一起来了解什么是通常所说的面向对象程序设计(Object Oriented Programming)。

在之前几篇教程中,我们了解了类的定义和使用方法。

在类的使用中,包含了多态、封装和继承这三个显著的特点。

这三个特点,其实就是面向对象程序设计的三大特性。

它们让程序设计变得灵活,增加了程序的安全性(封装),具有良好的重用性(继承),易于扩展和维护(多态)。

如果大家对面向过程的程序设计做一些了解,会对这三个特性有更深的体会。

面向过程的程序设计,是通过一个main()函数定义程序要完成的任务,由一系列的子函数组成。

这些子函数,还会细化成更多的子函数,以满足程序的各种需求。

重复这样的过程,就是面向过程的程序设计。

所以,面向过程的程序设计把整个程序视为一系列的命令集合,即一组函数的顺序执行。函数细分为子函数,是为了降低程序的复杂度。

这就好像我们书写论文,main()函数就是提纲,子函数就是论题,子函数细分的子函数就是论点,数据是论据,而函数的计算过程就论证的过程。

论文的这种结构,逐层划分,逐一解决,就是为了降低整篇论文的复杂程度。

如果不进行划分,直接从头至尾书写论文,很显然难以完成。

这样的程序设计易于理解,但是,很明显具有很高的关联性。

在程序设计的过程中,一旦发生需求的改变,很难应对。

而面向对象的程序设计,不是以过程为导向,而是以对象为导向。

程序设计中,会划分出不同的类,通过类来创建出对象。

整个程序是一系列对象的集合,每个对象都可以接收其他对象发过来的消息,并处理这些消息,程序的执行过程就是一系列消息在各个对象之间传递和处理。

面向对象程序设计的优势还体现在它的五个基本原则。

单一职责原则:SRP(Single Responsibility Principle)

是指一个类的功能要单一,具备的特性与类要具有很高的相关性,降低了代码的复杂程度。

开放封闭原则:OCP(Open-Close Principle)

功能模块在扩展性方面应该是开放的而在修改性方面应该是封闭的。

例如饲养动物的示例中,允许增加喂养其它动物的功能,也就是说对于扩展是开放的。

而增加喂养其他动物的功能时,不用对已有的喂养函数进行修改,这是说明对于修改是封闭的。

里氏替换原则:LSP (the Liskov Substitution Principle)

子类应当可以替换超类并出现在超类能够出现的任何地方。

就像俗语说的“龙生龙,凤生凤,老鼠儿子会打洞”,需要打洞了,不管是老鼠爸爸还是老鼠儿子都能胜任。

但是,网上有一个关于鸟类的例子。

在生物学中,企鹅属于鸟类;不过,企鹅不会飞。

这特么就尴尬了。如果我们为鸟类定义飞的方法,企鹅这个子类无法实现这个方法。

很明显这违反了里氏替换原则。

那么是如何解决的呢?

解决方案是:鸟类不包含会飞的方法,而是定义一个会飞的鸟的子类和一个企鹅类,这样飞的方法就变成了子类的扩展,企鹅类也就不需要对飞的方法进行处理,不再违反里氏替换原则。

依赖倒置原则:DIP(the Dependency Inversion Principle)

具体依赖抽象,上层依赖下层。这样的依赖是倒置的。

例如饲养动物的示例中:

  • 各个动物类具有抽象的特性,饲养员类是具体的实现。
  • 进食是饲养的前提条件,没有进食无需饲养,所以动物类是下层,饲养类是上层。
  • 在饲养动物这一功能的具体实现时,依赖的是各个动物进食的特性,没有进食特性,则无法实现饲养。(具体依赖抽象)
  • 并且,只要具备进食特性的动物,都可以被饲养,而不是,依赖新增一种饲养方法。(底层不能依赖上层)

接口分离原则:ISP(the Interface Segregation Principle)

接口分离原则指在设计时,多个专用接口优于一个单一的通用接口。每个接口可以为单一的客户程序调用;这样能够避免,当某个客户程序需求变化时,对其他客户程序带来影响。

这就好像家里的电源,如果总电源上,通过一个插座(通用接口)连接所有的电器,当一个电器发生故障需要维修,就需要断掉总电源,导致其他电器受到影响。

那么,如果总电源上分出多个插座,每个插座(专用接口)连接一个电器,维修的时候,就只需要断掉专用的插座电源,其他电器依然能够正常工作。

另外,在程序设计中,大家还要理解耦合和内聚的概念。

这里,我偷懒引用网络上的一段内容,大家自行理解。

耦合

简单地说,软件工程中对象之间的耦合度就是对象之间的依赖性。指导使用和维护对象的主要问题是对象之间的多重依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。

耦合可以分为以下几种,它们之间的耦合度由高到低排列如下:

  • 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
  • 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
  • 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
  • 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
  • 标记耦合 。若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块B和C之间存在一个标记耦合。
  • 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据。
  • 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。

耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。

内聚与耦合

内聚:标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。

总结

程序讲究的是低耦合,高内聚。

就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。

内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。

在进行软件设计时,应力争做到高内聚,低耦合。

转载请注明:魔力Python » Python3萌新入门笔记(29)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (5)

  1. 头像
    楼主,有关于新手爬虫的分享教程吗。
    LUH7年前 (2018-02-23)回复
    • 小楼一夜听春语
      笔记中有使用urllib模块的相关内容
      小楼一夜听春语7年前 (2018-02-23)回复
  2. 头像
    小楼你后面说的这些具体想说什么我看不懂,要遵循,还有怎么用啊,求解
    平常心7年前 (2018-05-01)回复
    • 小楼一夜听春语
      面向对象编程的概念和基本设计原则,多做项目慢慢理解吧。
      小楼一夜听春语7年前 (2018-05-03)回复
  3. 头像
    有没接口自动化的教程分享
    搬砖5年前 (2020-01-02)回复