
基础篇
Everybody Knows Design Patterns
第0章 启程之前,请不要错过我
0.1 Python精简入门
设计模式与编程语言没有关系,它是对面向对象思想的灵活应用和高度概括,你可以用任何一种语言来实现它,但还是需要用一种语言来举例。除特别说明外,本书的所有示例源码,均采用 Python 实现。如果你初次接触 Python,请务必先阅读本章的内容;如果你已经很熟悉Python,可直接跳过本章的内容。
0.1.1 Python的特点
Python崇尚优美、清晰、简单,是一种优秀并被广泛使用的语言。
与Java和C++这些语言相比,Python最大的几个特点是:
(1)语句结束不用分号“;”。
(2)代码块用缩进来控制,而不用大括号“{}”。
(3)变量使用前不用事先声明。
从其他语言刚转到Python的时候可能会有点不适应,用一段时间就好了!
个人觉得,在所有的高级计算机语言中,Python是最接近人类的自然语言的。Python的语法、风格都与英文的书写习惯非常接近,Python 的这种风格被称为 Pythonic。如条件表达式,在Java和C++语言中是这样的:

而在Python语言中是这样的:

有没有觉得第二种方式更接近人类的自然思维?
0.1.2 基本语法
1.数据类型
Python是一种动态语言,定义变量时不需要在前面加类型说明,而且不同类型之间可以方便地相互转换。Python有五个标准的数据类型:
(1)Numbers(数字)
(2)String(字符串)
(3)List(列表)
(4)Tuple(元组)
(5)Dictionary(字典)
其中 List、Tuple、Dictionary 为容器,将在下一部分介绍。Python 支持四种不同的数字类型:int(有符号整型)、float(浮点型)、complex(复数)(说明:Python 3中已去除long类型,与int类型合并)。
每个变量在使用前都必须赋值,变量赋值以后才会被创建。
源码示例0-1

输出结果:


2.常用容器
1)List
List(列表)是Python中使用最频繁的数据类型,用“[]”标识。列表可以完成大多数集合类的数据结构实现,类似于Java中的ArrayList和C++中的Vector。此外,一个List中还可以同时包含不同类型的数据,支持字符、数字、字符串,甚至可以包含列表(即嵌套)。
(1)列表中值的切割也可以用到变量[头下标:尾下标],这样就可以截取相应的列表,从左到右索引默认从0开始,从右到左索引默认从-1开始,下标可以为空(表示取到头或尾)。
(2)加号(+)是列表连接运算符,星号(*)是重复操作。
源码示例0-2

输出结果:


2)Tuple
Tuple(元组)是另一种数据类型,用“()”标识,内部元素用逗号隔开。元组不能二次赋值,相当于只读列表,用法与List类似。Tuple相当于Java中的final数组和C++中的const数组。
源码示例0-3

输出结果:

3)Dictionary
Dictionary(字典)是Python中除列表以外最灵活的内置数据结构类型。字典用“{ }”标识,由索引(key)和它对应的值value组成。相当于Java和C++中的Map。
列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典中的元素通过键存取,而不通过偏移存取。
源码示例0-4


结果:

3.类的定义
使用class语句来创建一个新类,class之后为类的名称并以冒号结尾,实例如下:

类的帮助信息可以通过 ClassName._doc_查看,类体(class_suite)由类成员、方法、数据属性组成,举例如下。
源码示例0-5

其中_init_为初始化函数,相当于构造函数。
1)访问权限
● _foo_:定义的是特殊方法,一般是系统定义名字,类似_init_()。
● _foo:以单下画线开头时表示的是 protected 类型的变量,即保护类型只允许其本身与子类进行访问,不能用于 from module import *。
● __foo:以双下画线开头时,表示的是私有类型(private)的变量,即只允许这个类本身进行访问。
2)类的继承
类的继承语法结构如下:

Python中继承中的一些特点:
(1)在继承中基类的初始化方法_init_()不会被自动调用,它需要在其派生类的构造中亲自专门调用。
(2)在调用基类的方法时,需要使用super()前缀。
(3)Python总是首先查找对应类型的方法,不能在派生类中找到对应的方法时,它才开始到基类中逐个查找(先在本类中查找调用的方法,找不到才去基类中找)。
如果在继承元组中列了一个以上的类,那么它就被称作“多重继承”。
3)基础重载方法
Python的类中有很多内置的基础重载方法,我们可以通过重写这些方法来实现一些特殊的功能。这些方法如表0-1所示。
表0-1 基础重载方法

0.1.3 一个例子让你顿悟
我们将一段 Java 代码对应到 Python 中来实现,进行对比阅读,相信你很快就能明白其中的用法。
源码示例0-6 Java代码


源码示例0-7 对应的Python代码



源码示例0-6和源码示例0-7的结果是一样的,如下:

0.1.4 重要说明
(1)为了降低程序复杂度,本书用到的所有示例代码均不考虑多线程安全,望借鉴源码的读者注意。
(2)本书所有源码均在Python 3.6.3下编写,Python 3.0以上都可以正常运行。
(3)源码地址:https://github.com/luoweifu/PyDesignPattern,本书所有源代码可在此免费阅读和下载。
0.2 UML精简概述
0.2.1 UML的定义
UML是英文 Unified Modeling Language 的缩写,简称UML(统一建模语言),它是一种由一整套图组成的标准化建模语言,用于帮助系统开发人员阐明、设计和构建软件系统。
UML 的这一整套图被分为两组,一组叫结构性图,包含类图、组件图、部署图、对象图、包图、组合结构图、轮廓图;一组叫行为性图,包含用例图、活动图(也叫流程图)、状态机图、序列图、通信图、交互图、时序图。其中类图是应用最广泛的一种图,经常被用于软件架构设计中。
0.2.2 常见的关系
类图用于表示不同的实体(人、事物和数据),以及它们彼此之间的关系。该图描述了系统中对象的类型以及它们之间存在的各种静态关系,是一切面向对象方法的核心建模工具。
UML 类图中最常见的几种关系有:泛化(Generalization)、实现(Realization)、组合(Composition)、聚合(Aggregation)、关联(Association)和依赖(Dependency)。这些关系的强弱顺序为:泛化=实现 > 组合 > 聚合 > 关联 > 依赖。
1.泛化
泛化(Generalization)是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。
如:哺乳动物具有恒温、胎生、哺乳等生理特征,猫和牛都是哺乳动物,也都具有这些特征,但除此之外,猫会捉老鼠,牛会耕地,如图0-1所示。

图0-1 泛化
2.实现
实现(Realization)是一种类与接口的关系,表示类是接口所有特征和行为的实现。
如:蝙蝠也是哺乳动物,它除具有哺乳动物的一般特征之外,还会飞,我们可以定义一个IFlyable的接口,表示飞行的动作,而蝙蝠需要实现这个接口,如图0-2所示。

图0-2 实现
3.组合
组合(Composition)也表示整体与部分的关系,但部分离开整体后无法单独存在。因此,组合与聚合相比是一种更强的关系。
如:我们的电脑由CPU、主板、硬盘、内存组成,电脑与CPU、主板、硬盘、内存是整体与部分的关系,但如果让CPU、主板等组件单独存在,就无法工作,因此没有意义,如图0-3所示。

图0-3 组合
4.聚合
聚合(Aggregation)是整体与部分的关系,部分可以离开整体而单独存在。
如:一个公司会有多个员工,但员工可以离开公司单独存在,离职了依然可以好好地活着,如图0-4所示。

图0-4 聚合
5.关联
关联(Association)是一种拥有关系,它使一个类知道另一个类的属性和方法。关联可以是双向的,也可以是单向的。
如:一本书会有多个读者,一个读者也可能会有多本书,书和读者是一种双向的关系(也就是多对多的关系);但一本书通常只会有一个作者,是一种单向的关系(就是一对一的关系,也可能是一对多的关系,因为一个作者可能会写多本书),如图0-5所示。

图0-5 关联
6.依赖
依赖(Dependency)是一种使用的关系,即一个类的实现需要另一个类的协助,所以尽量不要使用双向的互相依赖。
如:所有的动物都要吃东西才能活着,动物与食物就是一种依赖关系,动物依赖食物而生存,如图0-6所示。

图0-6 依赖