Reference
python设计模式-UML类图中的结构及python实现
看懂UML类图和时序图
faif/python-patterns
前言
学习设计模式的时候,需要用到 UML 来理解每个设计模型。 一般的 UML 是假设以 Java 为实现语言,那么如何用 Python 来实现 UML 的各种结构呢?
工具
本文的UML图采用gliffy绘制。
Python版本2.7
类图
类图是由类和类之间的连接关系构成
这里只介绍类和抽象类
连接关系这里介绍泛化(generalization),实现(realize),聚合(aggregation),组合(composition),关联(assocation),依赖(dependency) 共六种。
类
抽象类(Java 中的接口 interface)
图示
interface
在 UML 中的图形为
其上半部分又一个 interface 的标示,在interface
中一般只给出接口的定义;
实现一般放在子类中实现。
代码
在 Python 中本身是没有接口或是抽象类这种概念的,但是可以通过抛出 NotImplementedError
这个异常来实现,或是通过 abc(Abstract Base Class) 这个 Python 库来实现。
通过抛异常实现
from __future__ import print_function
class Drawable:
def size(self):
raise NotImplementedError
def draw(self, x, y, scale=1.0):
raise NotImplementedError
class Circle(Drawable):
def size(self):
print('Circle')
def draw(self, x, y, scale=1.0):
print(x * y * scale)
c = Circle()
c.draw()
如果子类没有实现方法,在事例化的时候不会报错,只有调用到未实现的方法的时候才会报错。
使用 abc 模块来实现
这里暂不实现
from abc import ABCMeta, abstractmethod, abstractproperty
类 Class
图示
class
在 UML 中的图形为
整个图形分为三部分:上面为类名,中间为类属性,下面为类方法。
可以看到有
-
,+
,#
这三种符号,其分别代表私有,共有,保护。其中保护变量在 Python 中是不存在的。共有变量可以在类外被直接访问,且可以被子类继承;私有变量只能再次类中被访问且不可以被子类继承。
代码
from __funture__ import print_functiopn
class Flower(object):
def __init__(self, floral=None, leaf=None):
self.floral = floral
self.__leaf = leaf
def flowing(self):
print('flower')
def __grow(self):
print('grow grow')
以两条下划线抬头的变量为私有变量,方法为私有方法。
「Python其实可以在类外面访问到私有变量或方法。因为生成 Python 字节码的时候,编译器自动将含有 __
开头的属性或方法前加上了 _{classname}
,所以可以在类外通过 _Flower__leaf
来访问 __leaf
属性。但是不要尝试访问私有变量或方法」
连接关系
类的继承结构表现在 UML 中为:泛化 (generalize) 与实现 (realize)
继承关系为is - a
的关系;两个对象之间如果可以用is - a
类表示,就是继承关系:(..是..)
泛化关系(generalization)
图示
泛化关系在 UML 中的图形为
泛化关系用由一条直线和一个空心三角箭头标示,连接的两端都是类。在代码中的结构就是继承非抽象类。
Car
在现实中有实现,可用 Car
定义具体的对象。
代码
泛化关系表现为继承非抽象类
from __future__ import print_function
class Car(object):
def __init(self):
self.wheel = ['17']
self.body = 'Independent Suspension'
def run(self):
#get the car started
def horn(self):
print('car is coming')
class Suv(Car):
def horn(self):
print('Suv is coming')
class Jeep(Car):
def horn(self):
print('Jeep is coming')
实现(realize)
图示
实现在 UML 中的图形为
实现关系用一条虚线和空心三角箭头表示。
"交通工具" 作为一个抽象概念,在现实中并无法直接用来定义对象;只有指明具体的子类(Car
还是 Bicycle
)才可以用来定义对象。
代码
Car
和 Bicycle
继承了 Vehicle
这个抽象类。
from __future__ import print_function
class Vehicle(object):
def run(self):
raise NotImplementedError
class Car(Vehicle):
def run(self):
print('car run run')
class Bicycle(Vehicle):
def run(self):
print('bicycle run run')
关联关系(association)
关联关系用一条直线表示;它描述不同类的对象之间的结构关系;它是一种静态的关系,通常与运行状态无关,一般由常识等因素决定的;它一般用来定义对象之间静态的,天然的结构;所以,关联关系是一种 "强关联" 的关系。
比如,乘车人和车票之间就是一种关联关系;学生和学校就是一种关联关系;
图示
关联关系在 UML 中的图形为
关联关系为一条直线,关联关系默认不强调方向,表示对象间相互知道;如果需要强调方向,使用线状箭头,如图,表示 A 知道 B,B 不知道 A。
在代码中,关联对象通常是以成员变量的形式实现的。上图在代码中就是 A 中有一个属性为 B 类的实例。也可以为双箭头表示相互知道。
代码
class B(object):
pass
class A(object):
def __init__(self):
self.b = B()
依赖关系(dependency)
依赖关系描述一个对象在运行期间会用到另一个对象,与关联关系不同的是,它是一种临时性的关系,通常在运行期间产生,并且随着运行时的变化,依赖关系也可能发生变化。
显然依赖也有方向,双向依赖是一种非常糟糕的结构,我们总是应该保持单向依赖,杜绝双向依赖的产生。
注:在最终代码中,依赖关系体现为类构造方法及类方法的传入参数,箭头的指向为调用关系;依赖关系除了临时知道对方外,还是 "使用" 对方的方法和属性。
图示
从图中可以看出依赖关系为在类的方法中将另一个类当作参数传入。
代码
from __future__ import print_function
class People(object):
def __init__(self):
pass
def drive(self, vehicle):
vehicle.run()
class Vehicle(object):
def __init__(self):
pass
def run():
raise NotImplementedError
class Car(Vehicle):
def __init__(self):
pass
def run():
print('car start')
class Bicycle(Vehicle):
def __init__(self):
pass
def run():
print('bicycle start')
def main():
car = Car()
bicycle = Bicycle()
caleb = People()
caleb.drive(car)
caleb.drive(bicycle)
if __name__ == '__main__':
main()
在 People
的 drive()
方法中传入 Car
和 Bicycle
实例,调用 run()
方法,完成 People
的 drive()
方法。
组合关系(composition)
组合关系表示整体由部分构成,但是当整体不存在是部分也不存在,是一种强依赖关系。
图示
组合关系是由一个实心的菱形箭头表示,菱形箭头指向整体,公司有部门组成,当公司不存在了,部门也不存在了。
代码
class Company(object):
def __init__(self):
self.__departments = []
def build_department(self, department):
self.__departments.append(department)
class Department(object):
def __init__(self, title):
self.title = title
def main():
company = Company()
company.build_department(Department('Back End Development'))
company.build_department(Department('Front End Development'))
if __name__ = '__main__':
main()
聚合关系(aggregation)
聚合关系表示整体由部分构成,但是当整体不存在时部分还是可以存在的。
图示
聚合关系由一个空的菱形箭头表示,菱形箭头指向整体。当公司不存在时,人还是存在的。
组合关系和聚合关系由常识来区别的,在实现上区别不大。
代码
class Company(object):
def __init__(self):
self.__employees = []
def add_employee(self, people):
self.__employees.append(people)
class People(object):
def __init__(self, name):
self.name = name
def main():
company = Company()
p1 = People('Mike')
p2 = People('Jack')
company.add_employee(p1)
company.add_employee(p2)
if __name__ = '__main__':
main()