>>> from env_helper import info; info()
页面更新时间: 2020-03-28 08:22:42
操作系统/OS: Linux-4.19.0-8-amd64-x86_64-with-debian-10.3 ;Python: 3.7.3

9.8. 面向对象设计小结

专门探讨面向对象程序设计的图书很多,虽然这并非本书的重点,但还是要提供一些指南。

  • 将相关的东西放在一起。如果一个函数操作一个全局变量,最好将它们作为一个类的属性和方法。

  • 不要让对象之间过于亲密。方法应只关心其所属实例的属性,对于其他实例的状态,让它们自己去管理就好了。

  • 慎用继承,尤其是多重继承。继承有时很有用,但在有些情况下可能带来不必要的复杂性。要正确地使用多重继承很难,要排除其中的bug更难。

  • 保持简单。让方法短小紧凑。一般而言,应确保大多数方法都能在30秒内读完并理解。对于其余的方法,尽可能将其篇幅控制在一页或一屏内。

确定需要哪些类以及这些类应包含哪些方法时,尝试像下面这样做。

将有关问题的描述(程序需要做什么)记录下来,并给所有的名词、动词和形容词加上标记。

  • 在名词中找出可能的类。

  • 在动词中找出可能的方法。

  • 在形容词中找出可能的属性。

  • 将找出的方法和属性分配给各个类。

有了面向对象模型的草图后,还需考虑类和对象之间的关系(如继承或协作)以及它们的职责。为进一步改进模型,可像下面这样做。

记录(或设想)一系列用例,即使用程序的场景,并尽力确保这些用例涵盖了所有的功能。

透彻而仔细地考虑每个场景,确保模型包含了所需的一切。如果有遗漏,就加上;如果 有不太对的地方,就修改。不断地重复这个过程,直到对模型满意为止。

有了你认为行之有效的模型后,就可以着手编写程序了。你很可能需要修改模型或程序的某 些部分,所幸这在Python中很容易,请不用担心。只管按这里说的去做就好。

9.8.1. 小结

本章不仅介绍了有关Python语言的知识,还介绍了多个你可能一点都不熟悉的概念。下面来 总结一下。

  • 对象:对象由属性和方法组成。属性不过是属于对象的变量,而方法是存储在属性中的 函数。相比于其他函数,(关联的)方法有一个不同之处,那就是它总是将其所属的对象 作为第一个参数,而这个参数通常被命名为self。

  • 类:类表示一组(或一类)对象,而每个对象都属于特定的类。类的主要任务是定义其 实例将包含的方法。

  • 多态:多态指的是能够同样地对待不同类型和类的对象,即无需知道对象属于哪个类就 可调用其方法。

  • 封装:对象可能隐藏(封装)其内部状态。在有些语言中,这意味着对象的状态(属性) 只能通过其方法来访问。在Python中,所有的属性都是公有的,但直接访问对象的状态时 程序员应谨慎行事,因为这可能在不经意间导致状态不一致。

  • 继承:一个类可以是一个或多个类的子类,在这种情况下,子类将继承超类的所有方法。 你可指定多个超类,通过这样做可组合正交(独立且不相关)的功能。为此,一种常见 的做法是使用一个核心超类以及一个或多个混合超类。

  • 接口和内省:一般而言,你无需过于深入地研究对象,而只依赖于多态来调用所需的方 法。然而,如果要确定对象包含哪些方法或属性,有一些函数可供你用来完成这种工作。

  • 抽象基类:使用模块abc可创建抽象基类。抽象基类用于指定子类必须提供哪些功能,却 不实现这些功能。

  • 面向对象设计:关于该如何进行面向对象设计以及是否该采用面向对象设计,有很多不 同的观点。无论你持什么样的观点,都必须深入理解问题,进而创建出易于理解的设计。

9.8.2. 面向对象中的函数

在 Python 的面向对象功能中,有一些内置函数可以方便使用:

  1. callable(object) 判断对象是否是可调用的(如是否是函数或方法)

  2. getattr(object,name[,default]) 获取属性的值,还可提供默认值

  3. hasattr(object, name) 确定对象是否有指定的属性

  4. isinstance(object, class) 确定对象是否是指定类的实例

  5. issubclass(A, B) 确定A是否是B的子类

  6. random.choice(sequence) 从一个非空序列中随机地选择一个元素

  7. setattr(object, name, value) 将对象的指定属性设置为指定的值

  8. type(object) 返回对象的类型