类的五种关系 泛化聚合关联等应注意的问题和练习
- 格式:pptx
- 大小:457.61 KB
- 文档页数:83
类之间的⼏种关系类之间的关联关系UML类图中的关系分为四种:泛化、依赖、关联、实现;关联关系⼜可以细化为聚合和组合。
⼀、泛化(Generalization)泛化是⽗类和⼦类之间的关系,⼦类继承⽗类的所有结构和⾏为。
在⼦类中可以增加新的结构和⾏为,也可以覆写⽗类的⾏为。
⼀般⽤⼀个带空⼼箭头的实线表⽰泛化关系,UML图如下:泛化对应Java中继承关系,即⼦类继承⽗类中出private修饰外的所有东西(变量、⽅法等)。
⽰例代码:public class Animal {}public class Tiger extends Animal {}Tiger继承Animal,因此Tiger与Animal之间是泛化(继承)关系。
这个很好理解。
⼆、依赖(Dependency)依赖关系是⼀种使⽤关系,特定事物的改变有可能会影响到使⽤该事物的事物,反之不成⽴。
在你想显⽰⼀个事物使⽤另⼀个事物时使⽤。
⼀般⽤⼀条指向被依赖事物的虚线表⽰,UML图如下:通常情况下,依赖关系体现在某个类的⽅法使⽤另⼀个类作为参数。
代码⽰例:public class Screwdriver { //螺丝⼑,作为⼈类的⼯具,是⽤来被⼈类使⽤的}public class Person{public void screw(Screwdriver src){ //拧螺丝,需使⽤螺丝⼑}}Person类的screw()⽅法在使⽤时就得传⼊⼀个Screwdriver类型的参数,这样Screwdriver的改变就会影响到Person,因此Person与Screwdriver之间就是依赖关系(Person依赖于Screwdriver)。
三、关联(Association)是⼀种结构关系,说明⼀个事物的对象与另⼀个事物的对象相联系。
给定有关联的两个类,可以从⼀个类的对象得到另⼀个类的对象。
关联有两元关系和多元关系。
两元关系是指⼀种⼀对⼀的关系,多元关系是⼀对多或多对⼀的关系。
继承、实现、依赖、关联、聚合、组合的联系与区别分别介绍这几种关系:继承实现指的是一个class 类实现interface 接口(可以是多个)的功能;实现是类与接口之间最常 见的关系;在Java 中此类关系通过关键字implements 明确标识,在设计时一般没有争 议性;依赖可以简单的理解,就是一个类A 使用到了另一个类B ,而这种使用关系是具有偶然性的、、 临时性的、非常弱的,但是B 类的变化会影响到A ;比如某人要过河,需要借用一条船, 此时人与船之间的关系就是依赖;表现在代码层面,为类B 作为参数被类A 在某个method 方法中使用;Inte rfare指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可 以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java 中此类关系通过关键字extends 明确标识,在设计时一般没有争议性;b lnterface_BQlass_A ClaSs_B关联他体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友;这 种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而 且双方的关系一般是平等的、关联可以是单向、双向的;表现在代码层面,为被关联类B 以类属性的形式出现在关联类A 中,也可能是关联类A 引用了一个类型为被关联类B 的全 局变量;聚合聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a 的关系,此 时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象, 也可以为多个整体对象共享;比如计算机与CPU 、公司与员工的关系等;表现在代码层面, 和关联关系是一致的,只能从语义级别来区分;组合组合也是关联关系的一种特例,他体现的是一种contains-a 的关系,这种关系比聚合更强, 也称为强聚合;他同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生 命周期结束也就意味着部分的生命周期结束;比如你和你的大脑;表现在代码层面,和关联 关系是一致的,只能从语义级别来区分;对于继承、实现这两种关系没多少疑问,他们体现的是一种类与类、或者类与接口间的纵向 关系;其他的四者关系则体现的是类与类、或者类与接口间的引用、横向关系,是比较难区 分的,有很多事物间的关系要想准备定位是很难的,前面也提到,这几种关系都是语义级别Cl3ss A 十 depend<Qlass.B classBJ ;:;;VoidClass_B的,所以从代码层面并不能完全区分各种关系;但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联》依赖;聚合跟组合其实都属于关联只不过它们是两种特殊的关联因为本是同根生所以它们之间难 免会有相似之处下面让我们一起来看一下它们之间有何不同聚合与组合的概念相信不用我在此赘述大家就已经了解了下面直接上例子 程老师的《大话》里举大那个大雁的例子很贴切在此我就借用一下大雁喜欢热闹害怕孤独所 以它们一直过着群居的生活这样就有了雁群每一只大雁都有自己的雁群每个雁群都有好多 大雁大雁与雁群的这种关系就可以称之为聚合另外每只大雁都有两只翅膀大雁与雁翅的关 系就叫做组合有此可见聚合的关系明显没有组合紧密大雁不会因为它们的群主将雁群解散 而无法生存而雁翅就无法脱离大雁而单独生存一一组合关系的类具有相同的生命周期聚合关系图:构造函数不同雁群类:[csharp] view plaincopypublic class GooseGroup { public Goose goose; public GooseGroup(Goose goose) { this .goose = goose;} 10. }[csharp] view plaincopy1. 2. 3.4.5. 6.7. 8.9. 组合关系图:从从代码上看这两种关系的区别在于:1.public class GooseGroup2.{3.public Goose goose;4.5.6.public GooseGroup(Goose goose)7.{8.this.goose = goose;9.}10.}大雁类:[csharp] view plaincopy1.public class Goose2.{3.public Wings wings;4.5.public Goose()6.{7.wings=new Wings();8.}9.}[csharp] view plaincopy1.public class Goose2.{3.public Wings wings;4.5.public Goose()6.{7.wings=new Wings();8.}9.}聚合关系的类里含有另一个类作为参数雁群类(GooseGroup)的构造函数中要用到大雁(Goose)作为参数把值传进来大雁类(Goose)可以脱离雁群类而独立存在组合关系的类里含有另一个类的实例化大雁类(Goose)在实例化之前一定要先实例化翅膀类(Wings)两个类紧密耦合在一起它们有相同的生命周期翅膀类(Wings)不可以脱离大雁类(Goose)而独立存在信息的封装性不同在聚合关系中,客户端可以同时了解雁群类和大雁类,因为他们都是独立的而在组合关系中,客户端只认识大雁类,根本就不知道翅膀类的存在,因为翅膀类被严密的封装在大雁类中。
类之间的关系
1.继承关系(extends)
继承(泛化):指一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口),子类增加新功能。
也称为“is-a”关系。
2.实现关系(interface)
实现:类B实现接口A(可以是多个),那么类B和接口A的关系就是实现关系。
3.依赖关系
依赖:依赖关系是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系。
4.关联关系
关联:是对象之间的拥有关系,即“has a”关系。
如果B类中某个成员变量的类型是A类(接口),称B关联于A。
5.聚合关系
聚合:表示类A和类B之间是整体与部分的关系,成员对象是整体对象的一部分,但是成员对象可以脱离整体对象独立存在。
通常在定义一个整体类后,再分析这个整体类的组成结构,从而找出一些成员类该整体类和成员类之间就形成了聚合关系。
组合:也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。
一旦整体对象不存在,部分对象也将不存在,部分对象与整体对象之间具有同生共死的关系。
成员类是整体类的一部分,且整体类可以控制成员类的生命周期,即成员类的存在依赖于整体类。
UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现1.2.3.4.5.6.类与类图1 类(Class封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性、操作、关系的对象集合的总称。
2 在系统中,每个类具有一定的职责,职责指的是类所担任的任务,即类要完成什么样的功能,要承担什么样的义务。
一个类可以有多种职责,设计得好的类一般只有一种职责,在定义类的时候,将类的职责分解成为类的属性和操作(即方法)。
3 类的属性即类的数据职责,类的操作即类的行为职责一、依赖关系(Dependence依赖关系(Dependence):假设A类的变化引起了B 类的变化,则说名B类依赖于A类。
• 依赖关系(Dependency 是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系。
大多数情况下,依赖关系体现在某个类的方法使用另一个类的对象作为参数。
• 在UML中,依赖关系用带箭头的虚线表示,由依赖的一方指向被依赖的一方。
[java] view plaincopyprint?1. public class Driver2. {3. public void drive(Car car4. {5. car.move(;6. }7. ……8. }9. public class Car10. {11. public void move(12. {13. ......14. }15. ……16. }{car.move(;}……}public class Car{public void move({......}……}依赖关系有如下三种情况:1、A类是B类中的(某中方法的)局部变量;2、A类是B类方法当中的一个参数;3、A类向B类发送消息,从而影响B类发生变化;GeneralizationGeneralization A是B和C的父类,B,C具有公共类(父类)A,说明A是B,C的一般化(概括,也称泛化)• 泛化关系(Generalization也就是继承关系,也称为“is-a-kind-of”关系,泛化关系用于描述父类与子类之间的关系,父类又称作基类或超类,子类又称作派生类。
UML类图几种关系的总结在UML类图中,常见的有以下几种关系: 泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation),组合(Composition),依赖(Dependency)1. 泛化(Generalization)【泛化关系】:是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。
例如:老虎是动物的一种,即有老虎的特性也有动物的共性。
【箭头指向】:带三角箭头的实线,箭头指向父类2. 实现(Realization)【实现关系】:是一种类与接口的关系,表示类是接口所有特征和行为的实现.【箭头指向】:带三角箭头的虚线,箭头指向接口3. 关联(Association)【关联关系】:是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。
双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
【代码体现】:成员变量【箭头及指向】:带普通箭头的实心线,指向被拥有者上图中,老师与学生是双向关联,老师有多名学生,学生也可能有多名老师。
但学生与某课程间的关系为单向关联,一名学生可能要上多门课程,课程是个抽象的东西他不拥有学生。
下图为自身关联:4. 聚合(Aggregation)【聚合关系】:是整体与部分的关系,且部分可以离开整体而单独存在。
如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。
聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
【代码体现】:成员变量【箭头及指向】:带空心菱形的实心线,菱形指向整体5. 组合(Composition)【组合关系】:是整体与部分的关系,但部分不能离开整体而单独存在。
如公司和部门是整体和部分的关系,没有公司就不存在部门。
组合关系是关联关系的一种,是比聚合关系还要强的关系,它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。
类与类之间的关系展开全文一、关联关系1. 单向关联:从一个类中可以访问另一个类的成员,有这个类的引用。
2. 双向关联:两个类可以互相访问,互相有引用。
3. 自身关联:本类中调用自身self or this.4. 多维关联:多个类互相之间有单向关联也有双向关联,还可以有自身关联,多个维度的关联。
5. 一对多关联:一个类有多个类的引用。
6. 多对多关联:多个类互相之间有单向关联也有双向关联。
7. 当一个类的属性保存了对另一个类的一个实例的引用时,就产生了关联。
二、泛化关系:继承与实现1. 在 UML 中, 泛化关系用来表示类与类, 接口与接口之间的继承关系。
更准确的说是不仅有继承关系,还有类和接口的实现关系。
2. 泛化关系包括继承关系和实现关系。
三、聚合关系1. 聚合关联是一种特殊的关联. 它表示类间的关系是整体与部分的关系. 简言之: 关联关系中的一个类描述了一个较大的事物, 它由较小的事物组成.2. 聚合关系中一个大类由多个小类组成,但是没有这个大类,这些小类可以再次聚合成另外一个大类而继续使用,这是与组合关系的区别。
3. 聚合关系是关联关系的一种,是强的关联关系。
4. 聚合是整体和部分之间的关系,例如汽车由引擎、轮胎以及其它零件组成。
5. 聚合关系也是通过成员变量来实现的。
但是,关联关系所涉及的两个类处在同一个层次上,而聚合关系中,两个类处于不同的层次上,一个代表整体,一个代表部分。
6. 通俗的讲:“汽车”有一个引擎和四个轮胎,如果这个“汽车”毁了,它的引擎和轮胎还可以安在别的汽车上。
四、组合关系1. 整件拥有部件的生命周期, 所以整件删除时, 部件一定会跟着删除. 而且, 多个整件不可以同时共享同一个部件。
2. 组合关系中一个大类由多个小类组成,没有这个大类,小类不能存在。
3. 聚合关系是当描述一个大的事物时,大的事务可以包含小的事务,也可以不包含小的事物,比如图书馆和图书,而组合是一个大的事物的存在必须是由多个小的事务组成的,缺省了小的事务是不可以的。
7.下列各种图可用于静态建模的有( 。
( B ))。
( E )B. 由属性和关系来表示C.由操作来表示E. 选项 B 和 C。
(A )B. 由类的属性决定 E.选项A 和B3.顺序图反映对象之间发送消息的时间顺序,它与( )是同构的。
( C )A.用例图B.类图C.协作图D.状态图4.( )定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现。
( A ) A.用例图B.类图C.活动图D.状态图5.状态图包括( )。
( E ) A.类的状态B.状态之间的转换C.类执行的动作D. 触发类的动作的事件E. 所有以上选项6.下列属于状态的组成部分的有( AB ) A.名称 B.转移 C.条件D.事件、选择题1.类的结构是( A. 由代码来表示 D. 由对象的交互来表示2.类的行为是( A. 由一组操作决定 D. 由父类决定C .对类的每一个对象唯一的A.状态图B. 类图C. 序列图D.活动图8.下列不属于属性的可见性的是()。
(C)A.公有的B.私有的C.私有保护的D.保护的9.下面不属于用况之间关系的是()。
(A)A.友元B.扩展C.包含D.泛化10.通常对象有很多属性,下面仅能在对象内部访问的属性可见性限制是()。
(D)A. 公有的(public )B.受保护的(protected )C.友员(friendly )D.私有的(private )11.在用况之间,会有三种不同的关系,下列不是用况之间关系的是()。
(D)A. 包含(include )B.扩展(extend)C.泛化(generalization )D.关联(connect)12•在ATM自动取款机的工作模型中(用户通过输入正确的用户资料,从银行取钱的过程,下面不是“ Actor ”的是(。
(DA.用户B.ATM取款机C.ATM取款机管理员D.取款13.下面不是活动图中的基本元素的是(。
(DA.状态、分支B.分叉、汇合C.泳道、对象流D.用况、状态14.在下面的图例中,哪个用来描述活动(activity (。
一、简介类是对象的集合,展示了对象的结构以及与系统的交互行为。
类主要有属性(Attribute)和方法(Method)构成,属性代表对象的状态,如果属性被保存到数据库,此称之为“持久化”;方法代表对象的操作行为,类具有继承关系,可以继承于父类,也可以与其他的Class进行交互。
类图展示了系统的逻辑结构,类和接口的关系。
二、类的构成类主要有属性和方法构成。
比如商品属性有:名称、价格、高度、宽度等;商品的方法有:计算税率,获得商品的评价等等。
如下图三、类之间的关系(Relationship)关联(Association)两个相对独立的对象,当一个对象的实例与另外一个对象的特定实例存在固定关系时,这两个对象之间就存在关联关系。
1、单向关联A1->A2: 表示A1认识A2,A1知道A2的存在,A1可以调用A2中的方法和属性场景:订单和商品,订单中包括商品,但是商品并不了解订单的存在。
类与类之间的单向关联图:C#代码:代码表现为:Order(A1)中有Product(A2)的变量或者引用2、双向关联B1-B2: 表示B1认识B2,B1知道B2的存在,B1可以调用B2中的方法和属性;同样B2也知道B1的存在,B2也可以调用B1的方法和属性。
场景:订单和客户,订单属于客户,客户拥有一些特定的订单类与类之间的单向关联图C#代码3、自身关联同一个类对象之间的关联类与类之间自身关联图4、多维关联(N-ary Association)多个对象之间存在关联场景:公司雇用员工,同时公司需要支付工资给员工类与类之间的多维关联图:5、泛化(Generalization)类与类的继承关系,类与接口的实现关系。
场景:父与子、动物与人、植物与树、系统使用者与B2C会员和B2E会员的关系类与类之间的泛化图:系统的使用者包括:B2C会员、B2B会员和B2E会员6、依赖(Dependency)类A要完成某个功能必须引用类B,则A与B存在依赖关系,依赖关系是弱的关联关系。
类与类之间的关系⼀. 类与类之间的依赖关系⼤千世界, 万物之间皆有规则和规律. 我们的类和对象是对⼤千世界中的所有事物进⾏归类. 那事物之间存在着相对应的关系. 类与类之间也同样如此. 在⾯向对象的世界中. 类与类中存在以下关系: 1. 依赖关系 2. 关联关系 3. 组合关系 4. 聚合关系 5. 继承关系 6. 实现关系由于python是⼀⻔弱类型编程语⾔. 并且所有的对象之间其实都是多态的关系. 也就是说,所有的东⻄都可以当做对象来使⽤. 所以我们在写代码的时候很容易形成以上关系. ⾸先. 我们先看第⼀种, 也是这些关系中紧密程度最低的⼀个, 依赖关系.⾸先, 我们设计⼀个场景. 还是最初的那个例⼦. 要把⼤象装冰箱. 注意. 在这个场景中, 其实是存在了两种事物的. ⼀个是⼤象, ⼤象负责整个事件的掌控者, 还有⼀个是冰箱, 冰箱负责被⼤象操纵.⾸先, 写出两个类, ⼀个是⼤象类, ⼀个是冰箱类.class Elphant:def__init__(self, name): = namedef open(self):'''开⻔:return :return:'''passdef close(self):'''关⻔:return :return:'''passclass Refrigerator:def open_door(self):print("冰箱⻔被打开了")def close_door(self):print("冰箱⻔被关上了")冰箱的功能⾮常简单, 只要会开⻔, 关⻔就⾏了. 但是⼤象就没那么简单了. 想想. ⼤象开⻔和关⻔的时候是不是要先找个冰箱啊. 然后呢? 打开冰箱⻔. 是不是打开刚才找到的那个冰箱⻔. 然后装⾃⼰. 最后呢? 关冰箱⻔, 注意, 关的是刚才那个冰箱吧. 也就是说. 开⻔和关⻔⽤的是同⼀个冰箱. 并且. ⼤象有更换冰箱的权利, 想进那个冰箱就进那个冰箱. 这时, ⼤象类和冰箱类的关系并没有那么的紧密. 因为⼤象可以指定任何⼀个冰箱. 接下来. 我们把代码完善⼀下.class Elphant:def__init__(self, name): = namedef open(self, ref):print("⼤象要开⻔了. 默念三声. 开!")# 由外界传递进来⼀个冰箱, 让冰箱开⻔. 这时. ⼤象不⽤背着冰箱到处跑.# 类与类之间的关系也就不那么的紧密了. 换句话说. 只要是有open_door()⽅法的对象. 都可以接收运⾏ref.open_door()def close(self, ref):print("⼤象要关⻔了. 默念三声. 关!")passdef take(self):print("钻进去")class Refrigerator:def open_door(self):print("冰箱⻔被打开了")def close_door(self):print("冰箱⻔被关上了")# 造冰箱r = Refrigerator()# 造⼤象el = Elphant("神奇的⼤象")el.open(r) # 注意. 此时是把⼀个冰箱作为参数传递进去了. 也就是说. ⼤象可以指定任何⼀个冰箱.el.take()el.close(r)此时, 我们说, ⼤象和冰箱之间就是依赖关系. 我⽤着你. 但是你不属于我. 这种关系是最弱的.⽐如. 公司和雇员之间. 对于正式员⼯, 肯定要签订劳动合同. 还得⼩⼼伺候着. 但是如果是兼职. 那⽆所谓. 需要了你就来. 不需要你就可以拜拜了. 这⾥的兼职(临时⼯) 就属于依赖关系.我⽤你. 但是你不属于我.⼆. 关联关系.组合关系, 聚合关系其实这三个在代码上写法是⼀样的. 但是, 从含义上是不⼀样的. 1. 关联关系. 两种事物必须是互相关联的. 但是在某些特殊情况下是可以更改和更换的. 2. 聚合关系. 属于关联关系中的⼀种特例. 侧重点是xxx和xxx聚合成xxx. 各⾃有各⾃的 声明周期. ⽐如电脑. 电脑⾥有CPU, 硬盘, 内存等等. 电脑挂了. CPU还是好的. 还是 完整的个体 3. 组合关系. 属于关联关系中的⼀种特例. 写法上差不多. 组合关系⽐聚合还要紧密. ⽐ 如⼈的⼤脑, ⼼脏, 各个器官. 这些器官组合成⼀个⼈. 这时. ⼈如果挂了. 其他的东⻄ 也跟着挂了.⾸先我们看关联关系: 这个最简单. 也是最常⽤的⼀种关系. ⽐如. ⼤家都有男⼥朋友. 男⼈关联着⼥朋友. ⼥⼈关联着男朋友. 这种关系可以是互相的, 也可以是单⽅⾯的.class Boy:def__init__(self, name, girlFriend=None): = nameself.girlFriend = girlFrienddef have_a_dinner(self):if self.girlFriend:print("%s 和 %s⼀起去吃晚餐" % (, ))else:print("单⾝狗. 吃什么饭")class Girl:def__init__(self, name): = nameb = Boy("alex")b.have_a_dinner()# 突然⽜B了. 找到⼥朋友了g = Girl("如花")b.girlFriend = g # 有⼥朋友了. 6666b.have_a_dinner()gg = Girl("李⼩花")bb = Boy("wusir", gg) # 娃娃亲. 出⽣就有⼥朋友. 服不服bb.have_a_dinner() # 多么幸福的⼀家# 突然.bb失恋了. 娃娃亲不跟他好了bb.girlFriend = Nonebb.have_a_dinner() # ⼜单⾝了.注意. 此时Boy和Girl两个类之间就是关联关系. 两个类的对象紧密练习着. 其中⼀个没有了. 另⼀个就孤单的不得了. 关联关系, 其实就是我需要你. 你也属于我. 这就是关联关系. 像这样的关系有很多很多. ⽐如. 学校和⽼师之间的关系.School --- 学校Teacher--- ⽼师⽼师必然属于⼀个学校. 换句话说. 每个⽼师肯定有⼀个指定的⼯作机构. 就是学校. 那⽼师的属性中必然关联着学校.class School:def__init__(self, name, address): = nameself.address = addressclass Teacher:def__init__(self, name, school=None): = nameself.school = schools1 = School("⽼男孩北京校区", "美丽的沙河")s2 = School("⽼男孩上海校区", "迪⼠尼旁边")s3 = School("⽼男孩深圳校区", "南⼭区法院欢迎你")t1 = Teacher("⾦王", s1)t2 = Teacher("银王", s1)t3 = Teacher("海峰", s2)t4 = Teacher("⾼鑫", s3)# 找到⾼鑫所在的校区地址print(t4.school.address)想想, 这样的关系如果反过来. ⼀个⽼师可以选⼀个学校任职, 那反过来. ⼀个学校有多少⽼师呢? ⼀堆吧? 这样的关系如何来描述呢?def__init__(self, name, address): = nameself.address = addressself.t_list = [] # 每个学校都应该有⼀个装⼀堆⽼师的列表def add_teacher(self, teacher):self.t_list.append(teacher)class Teacher:def__init__(self, name, school=None): = nameself.school = schools1 = School("⽼男孩北京校区", "美丽的沙河")s2 = School("⽼男孩上海校区", "迪⼠尼旁边")s3 = School("⽼男孩深圳校区", "南⼭区法院欢迎你")t1 = Teacher("⾦王", s1)t2 = Teacher("银王", s1)t3 = Teacher("海峰", s2)t4 = Teacher("⾼鑫", s3)s1.add_teacher(t1)s1.add_teacher(t2)s1.add_teacher(t3)# 查看沙河校区有哪些⽼师for t in s1.t_list:print()好了. 这就是关联关系. 当我们在逻辑上出现了. 我需要你. 你还得属于我. 这种逻辑就是关联关系. 那注意. 这种关系的紧密程度⽐上⾯的依赖关系要紧密的多. 为什么呢? 想想吧⾄于组合关系和聚合关系. 其实代码上的差别不⼤. 都是把另⼀个类的对象作为这个类的属性来传递和保存. 只是在含义上会有些许的不同⽽已.三. 继承关系.在⾯向对象的世界中存在着继承关系. 我们现实中也存在着这样的关系. 我们说过. x是⼀种y, 那x就可以继承y. 这时理解层⾯上的. 如果上升到代码层⾯. 我们可以这样认为. ⼦类在不影响⽗类的程序运⾏的基础上对⽗类进⾏的扩充和扩展. 这⾥.我们可以把⽗类被称为超类或者基类. ⼦类被称为派⽣类.⾸先, 类名和对象默认是可以作为字典的key的class Foo:def__init__(self):passdef method(self):pass# __hash__ = Noneprint(hash(Foo))print(hash(Foo()))既然可以hash. 那就是说字典的key可以是对象或者类dic = {}dic[Foo] = 123dic[Foo()] = 456print(dic) # {<class '__main__.Foo'>: 123, <__main__.Foo object at0x103491550>: 456}虽然显⽰的有点⼉诡异. 但是是可以⽤的.接下来. 我们来继续研究继承上的相关内容. 在本节中主要研究⼀下self. 记住. 不管⽅法之间如何进⾏调⽤. 类与类之间是何关系. 默认的self都是访问这个⽅法的对象.class Base:def__init__(self, num):self.num = numdef func1(self):print(self.num)class Foo(Base):passobj = Foo(123)obj.func1() # 123 运⾏的是Base中的func1继续:class Base:def__init__(self, num):self.num = numdef func1(self):print(self.num)class Foo(Base):def func1(self):print("Foo. func1", self.num)obj.func1() # Foo. func1 123 运⾏的是Foo中的func1再来:class Base:def__init__(self, num):self.num = numdef func1(self):print(self.num)self.func2()def func2(self):print("Base.func2")class Foo(Base):def func2(self):print("Foo.func2")obj = Foo(123)obj.func1() # 123 Foo.func2 func1是Base中的 func2是⼦类中的总结. self在访问⽅法的顺序: 永远先找⾃⼰的. ⾃⼰的找不到再找⽗类的.接下来. 来难得:class Base:def__init__(self, num):self.num = numdef func1(self):print(self.num)self.func2()def func2(self):print(111, self.num)class Foo(Base):def func2(self):print(222, self.num)lst = [Base(1), Base(2), Foo(3)]for obj in lst:obj.func2() # 111 1 | 111 2 | 222 3再来. 还不够绕.class Base:def__init__(self, num):self.num = numdef func1(self):print(self.num)self.func2()def func2(self):print(111, self.num)class Foo(Base):def func2(self):print(222, self.num)lst = [Base(1), Base(2), Foo(3)]for obj in lst:obj.func1() # 那笔来吧. 好好算结论: self就是你访问⽅法的那个对象. 先找⾃⼰, 然后在找⽗类的.四. 类中的特殊成员什么是特殊成员呢? __init_()就是⼀个特殊的成员. 说⽩了. 带双下划线的那⼀坨. 这些⽅法在特殊的场景的时候会被⾃动的执⾏. ⽐如, 1. 类名() 会⾃动执⾏__init__() 2. 对象() 会⾃动执⾏__call__() 3. 对象[key] 会⾃动执⾏__getitem__() 4. 对象[key] = value 会⾃动执⾏__setitem__() 5. del 对象[key] 会⾃动执⾏ __delitem__() 6. 对象+对象会⾃动执⾏ __add__() 7. with 对象 as 变量会⾃动执⾏__enter__ 和__exit__ 8. 打印对象的时候会⾃动执⾏ __str__ 9. ⼲掉可哈希 __hash__ == None 对象就不可哈希了.创建对象的真正步骤:⾸先, 在执⾏类名()的时候. 系统会⾃动先执⾏__new__()来开辟内存. 此时新开辟出来的内存区域是空的. 紧随其后, 系统⾃动调⽤__init__()来完成对象的初始化⼯作. 按照时间轴来算. 1. 加载类 2. 开辟内存(__new__) 3. 初始化(__init__) 4. 使⽤对象⼲xxxxxxxxx类似的操作还有很多很多. 我们不需要完全刻意的去把所有的特殊成员全都记住. 实战中也⽤不到那么多. ⽤到了查就是了.。
UML的类图关系分为:关联、聚合组合、依赖、泛化(继承)UML的类图关系分为:关联、聚合/组合、依赖、泛化(继承)。
⽽其中关联⼜分为双向关联、单向关联、⾃⾝关联;下⾯就让我们⼀起来看看这些关系究竟是什么,以及它们的区别在哪⾥。
1、关联双向关联:C1-C2:指双⽅都知道对⽅的存在,都可以调⽤对⽅的公共属性和⽅法。
在GOF的设计模式书上是这样描述的:虽然在分析阶段这种关系是适⽤的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引⽤或指针。
对象引⽤本⾝就是有向的,更适合表达我们所讨论的那种关系。
所以这种关系在设计的时候⽐较少⽤到,关联⼀般都是有向的。
使⽤ROSE ⽣成的代码是这样的:class C1...{public:C2* theC2;};class C2...{public:C1* theC1;};双向关联在代码的表现为双⽅都拥有对⽅的⼀个指针,当然也可以是引⽤或者是值。
单向关联:C3->C4:表⽰相识关系,指C3知道C4,C3可以调⽤C4的公共属性和⽅法。
没有⽣命期的依赖。
⼀般是表⽰为⼀种引⽤。
⽣成代码如下:class C3...{public:C4* theC4;};class C4...{};单向关联的代码就表现为C3有C4的指针,⽽C4对C3⼀⽆所知。
⾃⾝关联(反⾝关联):⾃⼰引⽤⾃⼰,带着⼀个⾃⼰的引⽤。
代码如下:class C14...{public:C14* theC14;};就是在⾃⼰的内部有着⼀个⾃⾝的引⽤。
2、聚合/组合当类之间有整体-部分关系的时候,我们就可以使⽤组合或者聚合。
聚合:表⽰C9聚合C10,但是C10可以离开C9⽽独⽴存在(独⽴存在的意思是在某个应⽤的问题域中这个类的存在有意义。
这句话怎么解,请看下⾯组合⾥的解释)。
代码如下:class C9...{public:};class C10...{};组合(也有⼈称为包容):⼀般是实⼼菱形加实线箭头表⽰,如上图所⽰,表⽰的是C8被C7包容,⽽且C8不能离开C7⽽独⽴存在。