资讯专栏INFORMATION COLUMN

python设计模式-UML类图中的结构及python实现

shadajin / 1026人阅读

摘要:前言最近在看设计模式。类抽象类中接口图示接口在中的图形为可以看到再其上半部分有一个的表示。代码在中本事是没有接口和抽象类这一概念的,但是可以通过这个库来实现。在代码中的结构就是继承非抽象类。箭头指向抽象类。

前言

最近在看设计模式。在学习初期一直有一个问题困扰着我,那就是UML类图
中的各种结构用python代码是如何实现的?这个在初期可以说是深深的困扰着我的设计模式
学习之路。下面我将介绍一下我自己总结的实现,如果有错误也希望各位给指出,不胜感激。

工具介绍

本文的UML图采用Enterprise Architect绘制。
Python版本2.7.12
(在用了Enterprise Architect 后才知道他有从类图导出代码的功能,/捂脸
早知道就用这个学习各种结构的实现了。文末有介绍如何用Enterprise Architect 导出代码。)

类图

类图是由类和类之间的连接关系构成。
类我们这里只介绍类和抽象类。
连接关系我们介绍泛化(generalization)、实现(realize)、聚合(aggregation)、组合(compositon)、关联(assocation)和依赖(dependency)共六种。

抽象类(java中接口) 图示

接口在UML中的图形为

可以看到再其上半部分有一个interface的表示。在接口中一般只给出接口的定义
而实现一般放在子类和实现。

代码

在python中本事是没有接口和抽象类这一概念的,但是可以通过abc(Abstract Base Class)这个python库来实现。或者是通过抛出NotImplementedError这个异常来实现。

通过abc模块来实现
from abc import ABCMeta, abstractmethod, abstractproperty

class Drawable:
    __metaclass__ = ABCMeta

    @abstractproperty
    def size(self):
        pass

    @abstractmethod
    def draw(self, x, y, scale=1.0):
        pass


class Cicle(Drawable):
    def size(self):
        print "Cicle"

    def draw(self, x, y, scale=1.0):
        print str(x*y*scale)

c = Cicle()

如果在子类里面没有实现方法,当实例化子类的时候会报错。abc模块的具体使用这里就不介绍了。放上abc的 PEP3119

通过抛异常来实现
class Drawable1:
    def size(self):
        raise NotImplementedError

    def draw(self, x, y, scale=1.0):
        raise NotImplementedError


class Cicle(Drawable):
    def size(self):
        print "Cicle"

    def draw(self, x, y, scale=1.0):
        print str(x*y*scale)

c = Cicle()
c.draw()

这里如果子类没有实现方法,在实例化的时候不会报错。只有当调用到未实现的方法时候才会报错。这种通过abc的注册机制也可以实现。

图示

类的图示如下

可以看到整个图形分为三部分:上面为类名,中间为类属性,下面为类方法。
其中可以看到有- + 和# 三种符号,其分别代表私有、公有、保护。其中保护变量在python中是不存在的。
公有变量可以在类外被直接访问。且可以被子类继承,私有变量只能再此类中被访问且不可以被子类继承。

代码
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属性,当然这并没有什么意义。

连接关系 泛化(generalization) 图示

首先我们来看一下泛化关系的UML结构图。

连接器的是由一条直线和一个三角组成的,连接的两端都是类。在代码中的结构就是继承非抽象类。

代码
class Car(object):
    def __init__(self):
        self.wheel = ["11", "12", "21", "22"]
        self.body = "car body"

    def run(self):
        print self.wheel
        print self.body

    def horn(self):
        print "bbbbbbb"


class SUV(Car):
    def run(self):
        print "suv"
        super(SUV, self).run()


class Jeep(Car):
    def run(self):
        print "jeep"
        super(Jeep, self).run()

jeep = Jeep()
jeep.run()
jeep.horn()

我们可以看到Jeep和SUV继承了Car这个非抽象类

实现(realize) 图示

从图中可以看出实现关系为一个三角箭头加一段虚线构成。箭头指向抽象类。
在代码中表现为继承抽象类。

代码
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"

代码中Car和Bicycle继承了Vehicle这个抽象类。

关联关系(assocation)

关联关系是用一条直线表示的;它描述不同类的对象之间的结构关系;它是一种静态关系, 通常与运行状态无关,一般由常识等因素决定的;它一般用来定义对象之间静态的、天然的结构; 所以,关联关系是一种“强关联”的关系;
比如,乘车人和车票之间就是一种关联关系;学生和学校就是一种关联关系;[1]

图示

关联关系为一条直线,可以有箭头,如图表示car知道Moter的存在而Moter不知道Car的存在。表现在代码中就是Car中有一个属性为Motor类的实例。也可以为双箭头表示互相知道。

代码
class Motor(object):
    pass

class Car(object):
    def __init__(self):
        self.motor = Motor()
依赖关系(dependency)

他描述一个对象在运行期间会用到另一个对象的关系.与关联关系不同的是,它是一种临时性的关系,通常在运行期间产生,并且随着运行时的变化; 依赖关系也可能发生变化;

显然,依赖也有方向,双向依赖是一种非常糟糕的结构,我们总是应该保持单向依赖,杜绝双向依赖的产生;
注:在最终代码中,依赖关系体现为类构造方法及类方法的传入参数,箭头的指向为调用关系;依赖关系除了临时知道对方外,还是“使用”对方的方法和属性;[1]

图示

从图中可以看出依赖关系为在类的方法中将另一个类当作参数传入。

代码
class People(object):
    def cooking(self, wok):
        wok.cook()

class Wok(object):
    def cook(self):
        print "cook"

我们在People的cooking方法中传入了Wok实例,调用其cook方法,完成people的cooking动作。

组合关系(composition)

组合关系表示整体由部分构成,但是当整体不存在时部分也不存在,是一种强依赖关系。

图示

从图中看到组合关系是由一个实心的菱形箭头表示,菱形箭头指向整体。 公司由部分组成。当公司不存在了,部门也就不存在了。

代码
class Company(object):
    def __init__(self):
        self.__departments = []

    def build_department(self, department):
        self.__departments.append(department)


class Department(object):
    def __init__(self, name):
        self.name = name


c = Company()
d1 = Department("1")
d2 = Department("2")
c.build_department(d1)
c.build_department(d2)
聚合关系(aggregation)

聚合关系表示整体由部分构成但是当整体不存在的时候部分也是可以存在的。

图示

从图中看到聚合关系由一个空心的菱形箭头表示, 菱形箭头指向整体。及公司是由人组成的。 当公司不存在的时候人还是可以多带带存在的。 组合关系和聚合关系由常识来区别的。在实现上区别不大。

代码
class Company(object):
    def __init__(self):
        self.__employees = []
    
    def add_employee(self, people):
        self.__employees.append(people)
        
class People(object):
    pass

c = Company()
p1 = People()
p2 = People()
p3 = People()
c.add_employee(p1)
c.add_employee(p2)
c.add_employee(p3)
如何从Enterprise Architect 导出代码

有点长我把这个再写一篇,
如何从Enterprise Architect 导出代码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/40951.html

相关文章

  • Python自动绘制UML图、函数调用图(Call Graph)

    摘要:借助,自动提取代码的动态调用流程图。绘制类图安装是一个开源图形可视化软件。循环曲线表示递归过程调用。绘制的常用工具有静态调用图等。包括模块之间的调用流程函数调用次数及耗时等。 ...

    widuu 评论0 收藏0
  • Python学习之路25-使用一等函数实现设计模式

    摘要:本篇主要讲述中使用函数来实现策略模式和命令模式,最后总结出这种做法背后的思想。 《流畅的Python》笔记。本篇主要讲述Python中使用函数来实现策略模式和命令模式,最后总结出这种做法背后的思想。 1. 重构策略模式 策略模式如果用面向对象的思想来简单解释的话,其实就是多态。父类指向子类,根据子类对同一方法的不同重写,得到不同结果。 1.1 经典的策略模式 下图是经典的策略模式的U...

    econi 评论0 收藏0
  • Learning PHP —— 设计模式 | Chap2:设计模式UML

    摘要:设计模式设计模式基本原则设计原则按接口而不是按实现来编程按接口而不是按实现编程是指,要将变量设置为一个抽象类或接口数据类型的实例,而不是一个具体实现的实例。例如父类的一个改变会逐级向下传递给子类实现,这可能会影响子类使用的某个算法。 设计模式 设计模式基本原则 设计原则 ① : 按接口而不是按实现来编程 按接口而不是按实现编程是指,要将变量设置为一个抽象类或接口数据类型的实例,而不是一...

    senntyou 评论0 收藏0
  • UML StarUml

    摘要:类之间的关系关联关系关联关系是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一个类对象与另一个类对象之间有联系。自关联在系统中可能会存在一些类的属性对象类型为该类本身,这种特殊的关联关系称为自关联。 UML UML:统一建模语言(Unified Modeling Language)。在 UML 系统开发中有三个主要的模型: 功能模型:从用户的角度展示系统的功能,包括用例图...

    NikoManiac 评论0 收藏0

发表评论

0条评论

shadajin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<