在程序中需要把世间万物抽象成相应的类,现实世界中物与物之间的关系和程序中类与类之间的关系相对应,因为世间万物是普遍联系的,所以程序中类与类之间也不是孤立的。在系统分析和框架设计中,根据面向对象机制的三大特性:封装、继承、多态,归纳和扩展出类与类之间六种不同的关系:

    - 依赖关系Dependency: 在局部变量,方法的形参,或者对静态方法的调用中实现

    - 关联关系Association: 在类的成员变量中实现,可以双向也可以单向

    - 聚合关系Aggregation: 强关联,整体与部分的关系,但是可分离

    - 组合关系Composition: 更强关联,整体与部分的关系,不可分离

    - 继承关系Generalization:类与类,或接口与接口之间的父子关系

    - 实现关系Implementation: 接口或抽象类定义好的操作集合,由实现类完成接口或抽象类的具体操作

其实从更宽泛的角度来说,类与类之间的关系其实只有三种:继承、实现、关联(依赖是一种弱关联,聚合和组合是关联中的特例)。继承和实现是类与类之间的纵向关系,比如A类继承了B类,C类实现了D接口;而关联是类与类之间的横向关系,类与类之间的关联关系从弱到强依次为:依赖 < 关联 < 聚合 < 组合。

纵向的继承和实现关系很容易理解,横向的关联关系相对复杂些,尤其是对生命周期的不同处理,关联、聚合、组合只能结合上下文语义才好判断。下面就重点介绍下这些容易相互混淆的关联关系。

依赖关系(Dependency)                                                                                                                                      

概念说明

可以简单地理解,依赖就是一个类A使用到了另一个类B,仅仅是“使用到”,类B本身并不属于类A,或者说类A并不拥有类B。依赖关系是偶然性的、临时性的,但是因为类B本身被类A引用到,所以B类的变化也会影响到类A。比较常见的场景就是人乘飞机从一地到另一地,飞机和人之间并没有所属关系,只是一种临时性的出行工具,此时人和飞机之间就是依赖关系。

代码实现

依赖关系在代码上体现为三种形式:

    - 类B作为类A方法的形参

    - 类B作为类A方法的局部变量

    - 类A调用类B的静态方法

# 类B作为类A方法的形参

class Person(object):
def flying(self, plane):
plane.fly() class Plane(object):
def fly(self):
print ("The plane is flying.") >>> person = Person()
>>> plane = Plane()
>>> person.flying(plane)
The plane is flying.
>>>
# 类B作为类A方法的局部变量

class Person(object):
def flying(self):
self.plane = Plane()
plane.fly() class Plane(object):
def fly(self):
print ("The plane is flying") >>> person = Person()
>>> person.flying()
The plane is flying.
>>>
# 类A调用类B的静态方法

class Person(object):
def flying(self):
Plane.fly() class Plane(object):
@staticmethod
def fly():
print ("The plane is flying.") >>> person = Person()
>>> person.flying()
The plane is flying.
>>>

UML类图

UML中使用带箭头的虚线表示,箭头指向表示调用关系,从类A指向类B

关联关系(Association)                                                                                                                                      

概念说明

关联关系一般长期性的、拥有性的关系,而且双方的关系一般是平等的,如学校与学生之间、老师与学生之间。被关联类B以类的属性形式出现在关联类A中,关联可以是单向的,也可以是双向的。

依赖关系与关联关系的区别有动静之分,依赖关系的偶然性和临时性说明了动态性,关联关系的长期性、拥有性静态地展示了对被关联类的引用。

代码实现

关联关系在代码上体现为四种形式:

    - 单向关联:单向拥有关系,只有一个类知道另一个类的属性和方法

    - 双向关联:双向拥有关系,双方都知道对方的属性和方法

    - 自身关联:自己关联自己,这种情况比较少但也有用到,如链表

    - 多重性关联:表示两个类的对象在数量上的对应关系,多重性可在关联线上用数字范围表示

          multiplicity: 多重性  

              1      仅为1

              *    从0到无穷大

           0..1    0 或者 1

            n..m    [n, m]之间的任何数

  

# 单向关联
class Student(object):
def __init__(self):
self.title = "Seno"
def study(self):
print ("Studying...") class School(object):
def __init__(self):
self.address = "ABC Street"
self.student = Student() def act(self):
print (self.student.title)
self.student.study() >>> school = School()
>>> school.act()
Seno
Studying...
>>>
# 双向关联

class Student(object):
def __init__(self):
self.school = School() class School(object):
def __init__(self):
self.student = Student()

    

# 自身关联

class Node(object):
def __init__(self):
self.next = Node()

UML类图

UML中使用直线箭头表示,箭头指向为被关联的类,从类A指向类B

单向关联

双向关联

自我关联

多重性关联

聚合关系(Aggregation)                                                                                                                                    

概念说明

聚合关系是也是关联关系的特例。普通关联关系的两个类一般处于同一平等层次上,而聚合关系的两个类处于不同的层次,是整体与部分的关系。聚合关系中的整体和部分是可以分离的,生命周期也是相互独立的,如公司与员工之间。

代码实现

聚合关系在代码上体现为:类A由类B聚合而成,类A包含有类B的全局对象,但类B的对象可以不在类A创建的时刻创建。

class School(object):
def __init__(self):
self.__students = [] def add_student(self, student):
self.__students.append(student) class Student(object):
pass >>> student = Student()
>>> school = School()
>>> school.add_student(student)
>>>

UML类图

UML中使用空心菱形+实线箭头表示,空心菱形边指向类A(整体),实现箭头边指向部分类B(部分)

组合关系(Composition)                                                                                                                                  

概念说明

组合关系也是关联关系的特例,属于强聚合,本身也表示整体与部分的关系,但是组合关系中的整体和部分是不可分离的,整体生命周期的结束时也是部分的生命周期到头时。如人和大脑。

聚合和组合其实都是关联的特例,都是整体与部分的关系。它们的区别在于整体和部分是否可分离,聚合的两个对象之间是可分离的,且具有各自的生命周期,而组合的两个对象往往表现为一种同命相连的关系。

代码实现

组合关系在代码上体现为在整体类的构造方法中直接实例化成员类,因为类组合关系中整体与部分是共生的。

class Person(object):
def __init__(self):
print ("Person Iinitialization Start")
self.__brain = Brain()
print ("Person Iinitialization End") def run(self):
print ("Running...") class Brain(object):
def __init__(self):
print ("Brain Initialization Start")
print ("Brain Initialization End") >>> person = Person()
Person Iinitialization Start
Brain Initialization Start
Brain Initialization End
Person Iinitialization End
>>> person.run()
Running...
>>>

UML类图

UML中使用实心菱形+实线箭头表示,实心菱形边指向类A(整体),实线箭头边指向类B(部分)

继承关系(Generalization)                                                                                                                              

概念说明

继承指的是子类继承父类、或子接口继承父接口的功能并增加自己新功能的过程,是两个类之间耦合度最大的关系之一。父类称为基类或超类,子类也称为派生类。子类可以继承自抽象类或普通类。

代码实现

继承关系在代码上体现为二种形式:

    - 子类继承自抽象类或普通类

    - 子接口继承自父接口:适用于Java


# 子类继承自抽象类,必须实现父类中@abstractmethod修饰的抽象方法
from abc import ABCMeta, abstractmethod class Animal(metaclass=ABCMeta):
def __init__(self):
self.name = "Animal" @abstractmethod
def run(self):
print ("Animal is running.") def play(self):
print ("Animal is playing.") class Dog(Animal):
def __init__(self):
self.name = "Dog" def run(self):
print ("Dog is running.") def __bark(self):
print ("Dog is barking.") class Cat(Animal):
def __init__(self):
self.name = "Cat" def run(self):
print ("Animal is running.") def play(self):
print ("Cat is running.") def __jump(self):
print ("Cat is jumping.") >>> dog = Dog()
>>> cat = Cat()
>>> dog.run()
Dog is running.
>>> dog.play()
Animal is playing.>>> cat.run()
Animal is running.
>>> cat.play()
Cat is running.>>>
# 子类继承自普通类,子类方法重写父类同名非私有方法

class Animal(object):
def __init__(self):
self.name = "Animal" def run(self):
print ("Animal is running.") def play(self):
print ("Animal is playing.") class Dog(Animal):
def __init__(self):
self.name = "Dog" def run(self):
print ("Dog is running.") def __bark(self):
print ("Dog is barking.") class Cat(Animal):
def __init__(self):
self.name = "Cat" def play(self):
print ("Cat is running.") def __jump(self):
print ("Cat is jumping.") >>> dog = Dog()
>>> cat = Cat()
>>> dog.run()
Dog is running.
>>> dog.play()
Animal is playing.>>> cat.run()
Animal is running.
>>> cat.play()
Cat is running.>>>

UML类图

UML中使用实线+空心箭头表示,箭头由子类指向父类、或子接口指向父接口

实现关系(Implementation)                                                                                                                            

概念说明

实现关系是指一个类实现一个或多个接口功能的过程,这里的接口更多的是一种契约或规范。实现是两个类之间或类与接口之间耦合度最大的关系之一,在这种关系中,类实现了接口或接口类中所声明的操作。

代码实现

实现关系在代码上体现为二种形式:

    - 类具体实现接口中所声明的操作:如Java中支持原生interface,可以直接implement

    - 类具体实现接口类中所声明的操作:如python中无原生interface,这里的接口类更多的是逻辑上的契约或规范

class Car(object):
def engine(self):
raise NotImplementedError class Benz(Car):
def engine(self):
print ("Benz is running.") class BMW(Car):
def engine(self):
print ("BMW is running.") >>> benz = Benz()
>>> bmw = BMW()
>>> benz.engine()
Benz is running.
>>> bmw.engine()
BMW is running.
>>>

UML类图

UML中使用虚线+空心箭头表示,箭头由实现类指向接口

Python设计模式 - 基础 - 类/接口之间的六种关系的更多相关文章

  1. Python设计模式 - 基础 - 封装 & 继承 & 多态

    面向对象的核心是对象,世间万物都可以看作对象,任何一个对象都可以通过一系列属性和行为来描述,可以包含任意数量和类型的数据或操作.类是用来描述具有相同属性和方法的所有对象的集合.类通常是抽象化的概念,而 ...

  2. 设计模式基础:类及类关系的UML表示

    设计模式基础:类及类关系的UML表示 2009-10-26 17:00 by 宗哥, 1891 阅读, 1 评论, 收藏, 编辑 UML中,类关系分为这几种,泛化(generalization), 实 ...

  3. Python设计模式 - UML - 类图(Class Diagram)

    简介 类图是面向对象分析和设计的核心,用来描述系统各个模块中类与类之间.接口与接口之间.类与接口之间的关系,以及每个类的属性.操作等特性,一般在详细设计过程中实施. 类图本身就是现实世界的抽象,是对系 ...

  4. C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态

    C#基础--类/接口/成员修饰符,多态.重载.重写,静态和非静态 类/接口/成员修饰符 C#修饰符---接口: 接口默认访问符是internal接口的成员默认访问修饰符是public C#修饰符--类 ...

  5. Python设计模式 - 基础 - 七大基本原则

    提倡使用设计模式,主要出发点就是实现代码复用,增加代码的扩展性和可维护性.如何设计出简洁.易懂.灵活.优美的代码结构的确是一门学问,透彻理解并践行如下七大原则通常都能取得基本满意的结果: - 单一职责 ...

  6. UML类图中的六种关系(物理设计阶段)

    UML类图中经常会用到各种箭头和线条来表示不同类或者接口之间的关系,因此非常好的理解各个图标的含义是很有必要的. 在物理设计阶段可以通过EA工具将类图搭建好,然后直接生成物理类,这样也可以减少物理设计 ...

  7. Java连载60-类之间的六种关系

    一.类之间的关系 1.泛化关系(UML图:实线空心三角形箭头,箭头指向被继承方) 类和类.接口与接口之间的继承称为泛化关系 public class A {} class B extends A{} ...

  8. Python 面向对象基础(类、实例、方法、属性封装)

    python是面向对象语言,一切皆对象. 面向过程: 变量和函数. “散落” 在文件的各个位置,甚至是不同文件中.看不出变量与函数的相关性,非常不利于维护,设计模式不清晰. 经常导致程序员,忘记某个变 ...

  9. 设计模式基础--Java接口和抽象类

    最近在看设计模式,感觉需要先好好区分下抽象类和接口. 一.抽象类 <Java编程思想>中这样定义:包含抽象方法的类叫做抽象类. 解释: 1.包含,说明抽象类中可以有其他的具体方法. 2.因 ...

随机推荐

  1. 解决使用C/C++配置ODBC链接中文显示为问号(?)的问题

    使用VS2015中使用OBDC连接到数据库时,数据库可以正常显示,但是在VS上输出是乱码,如图: 在数据库中course表显示: vs程序结果显示: 查找原因,因为char默认读ascii型,只读到1 ...

  2. 同一个windows server 部署多个tomcat

    只需要修改tomcat目录下conf下的server.xml文件即可,修改地方有三个,把下面这几个端口修改了为不同的端口即可,例如我把这几个端口统一减1了 <Server port=" ...

  3. 20165308 2017-2018-2 《Java程序设计》课程总结

    20165308 2017-2018-2 <Java程序设计>课程总结 一.每周作业及实验报告链接汇总 我期待的师生关系 学习基础和c语言调查 Linux 安装及学习 第一周学习总结 第二 ...

  4. redis 延时任务 看一篇成高手系列2

    引言 在开发中,往往会遇到一些关于延时任务的需求.例如 生成订单30分钟未支付,则自动取消 生成订单60秒后,给用户发短信 对上述的任务,我们给一个专业的名字来形容,那就是延时任务.那么这里就会产生一 ...

  5. Maya中输出alembic文件的方法

    Maya中输出alembic文件是有现成api调用的,与maya中大部分api一样,这个功能参数的传入是非常类似mel的,本质上讲都是kwargs类型的参数,所以我们传入的参数就需要整理成类似于mel ...

  6. 减小delphi体积的方法

    1.关闭RTTI反射机制  自从Delphi2010中引入了新的RTTI反射机制后,编译出来的程序会变得很大,这是因为默认情况下 Delphi2010 给所有类都加上了反射机制.而我们的工程并不每每都 ...

  7. [UE4]Button

    一.按钮有4种状态:Normal(普通状态).Hovered(鼠标悬停状态).Pressed(鼠标按下状态).Disabled(禁用状态),可以分别给每种状态设置样式. 二.按钮有如图所示的5个事件, ...

  8. Window10下安装sbt

    参考:https://segmentfault.com/a/1190000002474507 下载:https://dl.bintray.com/sbt/native-packages/sbt/0.1 ...

  9. 杂谈1.py

    Python命名规则: 1. 组成:数字/字母/下划线 只能以字母,下划线开头 不能包含空格 避免Python关键字和函数名 简短且具有描述性 描述数据形态及支持操作 Python动态类型 变量无类型 ...

  10. ORA-00911: invalid character 包含中文报错

    SQL在pl下正常执行在vs里报错ORA-00911: invalid character. 1.检查SQL末尾是否含有";" 去掉 2.sql包含中文报错 string sql ...