在软件设计中,一个设计的基本原则就是:高内聚、低耦合。这句话的本质就是要降低模块与模块,实体与实体之间的关系,特别是相互之间的关系,尽可能把实体对外关系的数量和复杂度降低到最低。
实体之间的关系是导致系统复杂系统的关键,本文就是要探讨面向对象中特种实体之间的各种关系。
关系是指万事万物之间相互作用、相互影响的状态。
人与人之间在活动过程中直接的心理上的关系或心理上的距离。
UML是用图形的方式描述各种实体之间的关系。
哲学中几个基本观点,都会体现在UML图的设计中。
物质与意识
物质与意识的辩证关系
物质的内在运动规律与人的主观能动性的关系
事物与事物的联系
事物普遍联系的原理 =》 静态与动态联系。
事物发展变化的原理 =》动态发展
事物与事物之间竞争与合作
矛盾普遍性的原理
矛盾特殊性的原理
矛盾的普遍性与特殊性关系原理
主要矛盾与次要矛盾相互关系原理
矛盾的主要方面与次要方面相互关系原理
事物的发展变化
内因与外因相互作用的原理
量变与质变相互关系原理
事物的发展前进与曲折性统一原理
人的认识与事物之间的关系
认识与实践相互关系原理
现象与本质相互关系原理
感性与理性相关关系原理‘’
改造客观实践与改造主观世界相互关系原理
人与社会
社会存在与社会意识之间相互关系原理
人的价值原理
可以看出,关系在哲学原理中无处不在,事物之间的关系使得整个系统变得异常的复杂。
一个系统的复杂性,体现在各个实体之间关系的复杂性上。
高内聚、低耦合的软件设计原则本质就是要降低模块与模块,实体与实体之间的关系。
讲关系,我们首先是肯定了关系的存在。
关系是一种“有”,没有关系,我们又谈何关系。但是,必须指出的是,关系的存在不同于关系者的存在,不同于物本身的存在。
说到关系,我们首先要追问的是谁与谁的关系?关系是关系者之间的关系,没有关系者,便没有关系。当然,如果其中的某个关系者灭失以后,我们还可以说,关系作为一种过去时,曾经存在着。
世界上究竟是先有物,还是先有关系?应该说,有物才有物与物之间的关系,关系不可能先于物的存在而存在。
有人提出先于宇宙而存在着宇宙关系,先于关系者而存在着关系,这种观点正如看到自然界受到自然规律的支配,必有一种规律先于自然界存在一样,不过是一种毫无意义的臆想。单纯的关系仅仅是无源之光,无源之热,无源之声。抛开光源讲光,抛开热源讲热,抛开声源讲声,进而否定这些本源的存在是错误的。
更准确一点说,物以及物之间的关系是同时存在的,不可能存在一种与外界没有任何关系的物质!!!当一个新的事物诞生时,也同时诞生了该物与外界的关系!!!
关系对于关系者的决定作用,关系决定关系者的产生限于以下情形:先有A和B,A与B之间的关系决定了C的产生。这种情形无疑说明了一个相反的道理:先有关系,而后有关系者。即某种关系的存在意味着那个未曾产生的某物必然产生为某物。
然而,没有A和B作为关系者,首先没有A和B 的关系,同时也预示着,不可能产生并存在A、B与C的关系。譬如夫妻之间关系的首先存在,然后预设了子女的诞生。岂不知夫妻之间的关系并不是凭空产生的,没有夫或妻,何来夫妻关系?此为其一;其二,夫妻之间的关系仅仅是预示了子女的诞生,并不是所有的夫妻关系最终都会诞生子女;其三,子女的诞生决定了夫妻关系到父母关系的演变。没有子女,则没有与父母的关系,也没有具体的父子关系和母子关系。
世界本身是普遍联系着的。每一个事物都是与其他事物存在着各种各样的关系。有人把关系者命名为“个在”,即单独存在的个体。这种所谓的“个在”不过是人为的分析、认定与区分,是把关系者与关系人为地割裂开来;而抛开关系讲个在与抛开个在讲关系同样是错误的。原因很简单,世界上不存在与其他事物不发生关系的孤立个在,也不存在没有(或缺失)关系者的单纯关系。
世界上各种事物之间的关系是复杂的。事物的多样性,决定了事物之间关系的复杂性。事物之间的关系从发展变化的趋势上分析,可以分为历史关系,即过去存在着的关系;现实关系,即现实存在着的关系,以及未来可能的关系。
事物本身的性质决定了关系的性质,即关系者的性质决定了关系的性质。有什么样的关系者,才会有什么样的关系。事物在不断变化,事物之间的关系也随之在不断地变化。事物的变化决定其与外界关系的变化。
任何事物都会因外界的关系而处于“被”如何的状态之中。一事物不仅具有自身的规定性,而且通过关系接受外在的规定。譬如,一个人在家庭内部关系中的角色被定位为父亲,在单位内部关系中的角色被定位为同事。一事物由于自身的内部规定而设定了与外部的关系,外界通过与该事物的关系对其发生影响。一粒种子放在与沙漠、阳光的关系中会逐渐干瘪,放在与土壤、水、适宜的温度的关系中会长出小苗。
以上我们说的是真实的客观的存在着的关系,从哲学的更抽象的意义上讲,还有一种关系需要另外说明,这种关系就是“没有关系的关系”。没有关系,其实也是一种抽象意义的“关系”,也需要作为一种“关系”予以关注。两个关系者之间彼此还没有发生任何关系,事实上恰恰意味着一种“关系”状态。
普遍联系作为一般哲学范畴,通常是指事物或现象之间以及事物内部要素之间相互连结、相互依赖、相互影响、相互作用、相互转化等相互关系。
在无限的宇宙中,联系不是个别事物之间暂时的、特殊的关系,而是一切事物、现象和过程所共有的客观的、普遍的本性;任何事物都不能孤立地存在,都同其他事物发生着联系;世界是万事万物相互联系的统一整体;任何事物都是统一的联系之网上的一个部分、成分或环节,都体现着普遍的联系。
世界上的一切事物、一切过程都可以分解为若干部分,整体是由它的各个部分构成的,它不能先于或脱离其部分而存在,没有部分就无所谓整体;部分是整体的一个环节,离开整体的要素只是特定的他物而不成其为部分,没有整体就无所谓部分。整体和部分的划分是相对的,某一事物可以作为整体包容着部分,该事物又可以作为部分从属于更高层次的整体。
整体是部分的有机统一、集合。集合中的各个部分不是单纯地叠加或机械地堆积在一起的,而是以一定的结构形式互相联系、相互作用着的,从而使事物的整体具有某种新的属性和规律。事物作为整体所呈现的特有属性和特有规律,与它的各个部分在孤立状态下所具有的属性和规律有质的区别,它不是各个部分属性和规律的相加。
部分是整体的一环。事物作为整体中的部分与它作为相对独立的对象也有质的区别。在某些情况下,当整体分解时,其部分可能以原来的状态游离出该整体作为独立物存在,但当它在整体当中时则总是以某种方式与其他部分结合着,在整体中“分享”或带上整体性;在更多的情况下,整体中的部分不能以原来的状态游离出来,当部分脱离整体或整体分解时,其部分就改变其性质或形态而成为他物。不论在哪种情况下,构成整体的各个部分都是在改变其地位、性质或形态的情况下“进入”整体的。
事物的整体及其各个部分都处于不断运动变化中,并且受到环境改变的制约。事物的部分发生变化会影响整体,乃至破坏原来的整体,构成新的整体;整体的变化也会影响其各个部分,排除某些部分或吸引新的环节成为其部分。部分与整体之间的关系不是静态的,而是动态的。
整体和部分的范畴有重要的认识论意义。在认识过程中,人们总是先对整体有大致的了解,继而分析研究其部分,并在这个基础上综合地、具体地认识整体。认识事物在整体上所具有的属性和规律是重要的,在科学认识的活动中,不仅要把握对象的组成要素,还必须把握诸要素间的结构和结合方式,以及由关系结构所产生的单个要素所没有的特性。揭示事物的各要素是深入了解整体的基础,而有了整体性的知识又可以进一步认识其部分。在认识世界时,不能只见部分不见整体。科学的认识方法要求人们既要研究部分,又要考察整体,并把二者有机地结合起来。现代科学在不断分化的基础上日益表现出相互渗透、相互交叉的趋势。由于现代社会生活和物质生产的规模更加扩大和复杂化,自然科学、社会科学都注重于综合性的研究,探讨各领域中整体和部分之间的相互关系,并且出现了着重研究整体结构、整体功能的系统科学和系统工程学。
局部与全局和部分与整体是同一层次的范畴,局部是整体(全局)中的部分,全局是由局部(部分)的结合构成的。全局与其各个局部的总和也有质的区别,它具有高于局部的整体性;局部是全局的基础又从属于全局。战略解决全局性问题,战术解决全局中某个局部的问题。制定社会发展战略、政治战略、军事战略、经济战略、科技战略,都要正确认识事物的整体,并根据全局性的要求使各个局部处于恰当的状态,使各项战术性措施符合战略的目标。毛泽东在论证局部和全局的关系时指出:有局部经验的人,有战役战术经验的人是能够明白更高级的全局性问题的,但必须用心思去想才会懂得全局性的东西;而懂得了全局性的东西就更会使用局部性的东西,因为局部是隶属于全局的,只有全局在胸才会在局部投下一着好棋;要认识全局性的东西,就必须把握矛盾的各个方面并抓住有决定意义的主要矛盾。
抽象与概括都是建立在比较基础上的,抽象是高级的分析,概括是高级的综合。抽象与概括是互相依存、相辅相成的。
(1)抽象 是在头脑里抽出一些事物的本质属性,而舍弃其非本质属性的思维方法。从事物的许多属性中抽出本质属性,一般要经历三个阶段:第一个阶段,通过分析,找出具体事物的个别属性。第二个阶段,通过比较,找到事物之间的共同属性。共同属性又有本质属性与非本质属性之分。第三个阶段,通过抽象抽取出事物的本质属性,而舍弃其非本质属性。本质属性指的是这类事物所独有而为其他类事物所没有的属性。
(2)概括 是在头脑里把抽象出来的事物的若干本质属性联合起来推广到一类事物,使之普遍化的思维方法。例如,我们把“人”能言语、能思维、能制造工具等本质属性联合起来医|学教育网搜集整理,推广到古今中外一切人的身上,指出:“凡是能言语、能思维、能制造和使用工具的动物,就是人。”这样就能概括出“人”的概念的内涵(定义)。
用于Actor与用例之间的关系
是一种继承关系,子用例是父用例的一种特殊形式,它继承了父用例的所有结构、行为、关系。其中三角箭头指向父用例,用于:
Actor 与 Actor之间
用来与用例之间
包含关系:基本用例的行为包含了另一个用例的行为,是比较特殊的依赖关系。
箭头方向由基本用例指向被包含用例。
执行基用例时,每次都必须调用被包含用例, 被包含用例也可以单独执行。
例1:
当可以从两个或两个以上的用例中提取公共行为时,应该使用包含关系。其中提取出来的公共用例成为抽象用例,而把原始用例变成基本用例或基础用例。箭头指向抽象用例。
说明:
阅读者在读书和借书的时候,都要登记记录,他们有登记记录这一共同的行为,所以把它提取出来作为一种抽象用例,借书和还书这两个基本用例中包含了登记记录这一抽象用例。
例2:
一个用例的功能太多时,可以使用包含关系建立若干个更小的用例。
说明:
一般用户有很多功能,其中包括各种信息的查看,这时可以建立一个查询信息这一个用例,然后下面在包含查看余额、查看上机记录、查看充值记录这三个小用例。
关系说明:表示用例与用例之间的关系;用于拓展用例对基础用例的增强;拓展用例是在特定条件出现时,才会被执行的用例。
表示方法:虚线箭头+<
举例说明:用户在登录过程中忘记了密码
扩展和包括关系的区别:
被扩展的用例,只有在某种特殊的情况下,执行主用例时,才会执行扩展用例。
包含关系的用例,每次执行主用例,都会执行扩展用例。
依赖关系(Dependence):假设A类的变化引起了B类的变化,则说名B类依赖于A类。
依赖关系(Dependency) 是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系。大多数情况下,依 赖关系体现在某个类的方法使用另一个类的对象作为参数。
在UML中,依赖关系用带箭头的虚线表示,由依赖的一方指向被依赖的一方。
//下面代码中,driver类依赖car类
public class Driver
{
public void drive(Car car)
{
car.move();
}
……
}
public class Car
{
public void move()
{
......
}
……
}
B依赖A的依赖关系有如下几种情况:
B在成员函数中的局部参数中使用了A, 但A并不是B的成员属性的一部分。
B的入口参数中,使用了A, 但A并不是B的成员属性的一部分。
B在成员函数中的函数调用中使用了A, 但A并不是B的成员属性的一部分。
泛化与继承是一对概念。站在父类看子类,称为泛化;站在子类看父类,称为继承。
泛化关系(Generalization):A是B和C的父类,B,C具有公共类(父类)A,说明A是B,C的一般化(概括,也称泛化)
泛化关系(Generalization)也就是继承关系,也称为“is-a-kind-of”关系,泛化关系用于描述父类与子类之间的关系,父类又称作基类或超类,子类又称作派生类。在UML中,泛 化关系用带空心三角形的直线来表示。
在代码实现时,使用面向对象的继承机制来实现泛化关系,如在Java语言中使用extends关键字、在C++/C#中使用冒号“:”来实现。
public class Person
{
protected String name;
protected int age;
public void move()
{
……
}
public void say()
{
……
}
}
public class Student extends Person
{
private String studentNo;
public void study()
{
……
}
泛化与继承,反应的一般和特殊之间的关系,被继承的类的所有成员属性和成员函数,都将为继承者的成员属性和成员函数。这是继承最重要的特性。
在UML当中,对泛化关系有三个要求:
子类与父类应该完全一致,父类所具有的属性、操作,子类应该都有;
子类中除了与父类一致的信息以外,还包括子类自身的额外的信息;
可以使用父类的实例的地方,也可以使用子类的实例,因为子类包含了父类所有的属性(数据结构)
是用来规定接口和实线接口的类或者构建结构的关系,接口是操作的集合,而这些操作就用于规定类或者构建的一种服务。
接口之间也可以有与类之间关系类似的继承关系和依赖关系,但是接口和类之间还存在一种实现关系(Realization),在这种关系中,类实现了接口,类中的操作实现了接口中所声明的操作。
在UML中,类与接口之间的实现关系用带空心三角形的虚线来表示。
public interface Vehicle
{
public void move();
}
public class Ship implements Vehicle
{
public void move()
{
……
}
}
public class Car implements Vehicle
{
public void move()
{
……
}
}
这种关系,有点类似继承关系,car继承了Vehicle接口的所有函数原型,但没有继承具体的实现,需要子类重新实现具体的功能。
关联关系(Association):类之间的联系,如客户和订单,每个订单对应特定的客户,每个客户对应一些特定的订单,再如篮球队员与球队之间的关联(下图所示)。
其中,关联两边的"employee"和“employer”标示了两者之间的关系,而数字表示两者的关系的限制,是关联两者之间的多重性。通常有“*”(表示所有,不限),“1”(表示有且仅有一个),“0...”(表示0个或者多个),“0,1”(表示0个或者一个),“n...m”(表示n到m个都可以),“m...*”(表示至少m个)。
• 关联关系(Association) 是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一类对象与另一类对象之间有联系。
• 在UML类图中,用实线连接有关联的对象所对应的类,在使用Java、C#和C++等编程语言实现关联关系时,通常将一个类的对象作为另一个类的属性。
• 在使用类图表示关联关系时可以在关联线上标注角色名。
1) 双向关联: 默认情况下,关联是双向的。
public class Customer
{
private Product[] products;
……
}
public class Product
{
private Customer customer;
……
}
2 ) 单向关联:类的关联关系也可以是单向的,单向关联用带箭头的实线表示.
public class Customer
{
private Address address;
……
}
public class Address
{
……
}
3) 自关联: 在系统中可能会存在一些类的属性对象类型为该类本身,这种特殊的关联关系称为自关联。
public class Node
{
private Node subNode;
……
}
4) 重数性关联: 重数性关联关系又称为多重性关联关系(Multiplicity),表示一个类的对象与另一个类的对象连接的个数。在UML中多重性关系可以直接在关联直线上增加一个数字表示与之对应的另一个类的对象的个数。
表示方式 |
多重性说明 |
1..1 |
表示另一个类的一个对象只与一个该类对象有关系 |
0..* |
表示另一个类的一个对象与零个或多个该类对象有关系 |
1..* |
表示另一个类的一个对象与一个或多个该类对象有关系 |
0..1 |
表示另一个类的一个对象没有或只与一个该类对象有关系 |
m..n |
表示另一个类的一个对象与最少m、最多n个该类对象有关系 (m<=n) |
public class Form
{
private Button buttons[];
……
}
public class Button
{
…
}
聚合关系(Aggregation):表示的是松耦合的整体和部分的关系,整体与部分可以分开.
聚合关系(Aggregation) 表示一个整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构,从而找出一些成员类,该整体类和成员类之间就形成了聚合关系。
在聚合关系中,成员类是整体类的一部分,即成员对象是整体对象的一部分,但是成员对象可以脱离整体对象独立存在。在UML中,聚合关系用带空心菱形的直线表示。
public class Car
{
private Engine engine; //
public Car(Engine engine)
{
this.engine = engine;
}
public void setEngine(Engine engine)
{
this.engine = engine; //eninee不是Car自己创建的,也不是Car new出来的对象
// engine与Car对象是分离的、独立的
}
……
}
public class Engine
{
……
}
如:电话机聚合一个外部件:话筒
电脑包括键盘、显示器,一台电脑可以和多个键盘、多个显示器搭配,确定键盘和显示器是可以和主机分开的,主机可以选择其他的键盘、显示器组成电脑;
聚合与被聚合对象之间,是可以分离的。
组合关系(Composition):也是整体与部分的关系,但是整体与部分不可以分开.
组合关系(Composition)也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在,部分对象与整体对象之 间具有同生共死的关系。
在组合关系中,成员类是整体类的一部分,而且整体类可以控制成员类的生命周期,即成员类的存在依赖于整体类。在UML中,组合关系用带实心菱形的直线表示。
public class Head
{
private Mouth mouth;
public Head()
{
mouth = new Mouth(); //Mounth是Head自己New出来的对象,Head消亡的时候,Mouth也会消亡。
}
……
}
public class Mouth
{
……
}
如:公司和部门,部门是部分,公司是整体,公司A的财务部不可能和公司B的财务部对换,
就是说,公司A不能和自己的财务部分开; 人与人的心脏。
组合与被组合对象之间是不可分离的,他们具有相同的生命周期!!!
也就是说,被组合对象是由组合对象创建的!!!!
同类图.....
状态与状态之间的唯一关系就是在事件的触发下,在不同的状态之间进行切换 。
泳道图:多个线程的流程图之间的相互交互关系!!!