Reference
python設計模式-UML類圖中的結構及python實現(xiàn)
看懂UML類圖和時序圖
faif/python-patterns
前言
學習設計模式的時候,需要用到 UML 來理解每個設計模型。 一般的 UML 是假設以 Java 為實現(xiàn)語言,那么如何用 Python 來實現(xiàn) UML 的各種結構呢?
工具
本文的UML圖采用gliffy繪制。
Python版本2.7
類圖
類圖是由類和類之間的連接關系構成
這里只介紹類和抽象類
連接關系這里介紹泛化(generalization),實現(xiàn)(realize),聚合(aggregation),組合(composition),關聯(lián)(assocation),依賴(dependency) 共六種。
類
抽象類(Java 中的接口 interface)
圖示
interface在 UML 中的圖形為

其上半部分又一個 interface 的標示,在interface中一般只給出接口的定義;
實現(xiàn)一般放在子類中實現(xiàn)。
代碼
在 Python 中本身是沒有接口或是抽象類這種概念的,但是可以通過拋出 NotImplementedError 這個異常來實現(xiàn),或是通過 abc(Abstract Base Class) 這個 Python 庫來實現(xiàn)。
通過拋異常實現(xiàn)
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()
如果子類沒有實現(xiàn)方法,在事例化的時候不會報錯,只有調用到未實現(xiàn)的方法的時候才會報錯。
使用 abc 模塊來實現(xiàn)
這里暫不實現(xiàn)
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 字節(jié)碼的時候,編譯器自動將含有 __ 開頭的屬性或方法前加上了 _{classname},所以可以在類外通過 _Flower__leaf 來訪問 __leaf 屬性。但是不要嘗試訪問私有變量或方法」
連接關系
類的繼承結構表現(xiàn)在 UML 中為:泛化 (generalize) 與實現(xiàn) (realize)
繼承關系為is - a的關系;兩個對象之間如果可以用is - a類表示,就是繼承關系:(..是..)
泛化關系(generalization)
圖示
泛化關系在 UML 中的圖形為

泛化關系用由一條直線和一個空心三角箭頭標示,連接的兩端都是類。在代碼中的結構就是繼承非抽象類。
Car 在現(xiàn)實中有實現(xiàn),可用 Car 定義具體的對象。
代碼
泛化關系表現(xiàn)為繼承非抽象類
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')
實現(xiàn)(realize)
圖示
實現(xiàn)在 UML 中的圖形為

實現(xiàn)關系用一條虛線和空心三角箭頭表示。
"交通工具" 作為一個抽象概念,在現(xiàn)實中并無法直接用來定義對象;只有指明具體的子類(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')
關聯(lián)關系(association)
關聯(lián)關系用一條直線表示;它描述不同類的對象之間的結構關系;它是一種靜態(tài)的關系,通常與運行狀態(tài)無關,一般由常識等因素決定的;它一般用來定義對象之間靜態(tài)的,天然的結構;所以,關聯(lián)關系是一種 "強關聯(lián)" 的關系。
比如,乘車人和車票之間就是一種關聯(lián)關系;學生和學校就是一種關聯(lián)關系;
圖示
關聯(lián)關系在 UML 中的圖形為

關聯(lián)關系為一條直線,關聯(lián)關系默認不強調方向,表示對象間相互知道;如果需要強調方向,使用線狀箭頭,如圖,表示 A 知道 B,B 不知道 A。
在代碼中,關聯(lián)對象通常是以成員變量的形式實現(xiàn)的。上圖在代碼中就是 A 中有一個屬性為 B 類的實例。也可以為雙箭頭表示相互知道。
代碼
class B(object):
pass
class A(object):
def __init__(self):
self.b = B()
依賴關系(dependency)
依賴關系描述一個對象在運行期間會用到另一個對象,與關聯(lián)關系不同的是,它是一種臨時性的關系,通常在運行期間產(chǎn)生,并且隨著運行時的變化,依賴關系也可能發(fā)生變化。
顯然依賴也有方向,雙向依賴是一種非常糟糕的結構,我們總是應該保持單向依賴,杜絕雙向依賴的產(chǎn)生。
注:在最終代碼中,依賴關系體現(xiàn)為類構造方法及類方法的傳入?yún)?shù),箭頭的指向為調用關系;依賴關系除了臨時知道對方外,還是 "使用" 對方的方法和屬性。
圖示

從圖中可以看出依賴關系為在類的方法中將另一個類當作參數(shù)傳入。
代碼
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)
聚合關系表示整體由部分構成,但是當整體不存在時部分還是可以存在的。
圖示

聚合關系由一個空的菱形箭頭表示,菱形箭頭指向整體。當公司不存在時,人還是存在的。
組合關系和聚合關系由常識來區(qū)別的,在實現(xiàn)上區(qū)別不大。
代碼
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()