UML系列 (三) 四种关系
1、继承是面向对象编程一大特点,如果两个对象A和B,可以描述为“B是A”,则表明B可以继承A。继承者还可以理解为是对被继承者的特殊化,因为它除了继承者的特性外,还具备自己独有的特性;继承一般可说成父类和子类或基类和派生类。如下面例子:
a 为了使子类的实例完全接替来自父类的成员,父类必须将该成员声明为虚拟的。在返回类型之前加上关键字“virtual”。
b 子类可以选择使用关键字“override”,将父类实现替换为它自己的实现。
c 这样方法重写,其实,是实现了“多态”。
d 多态是指不同的对象可以执行相同的动作,但要通过它们自己的实现代码来执行。
继承的优点是使得代码到了共享,避免了重复,增加了功能的可扩展性,而缺点为父类变,则子类就变,父类实现细节暴露给子类,增强了类与类之间的耦合性。
2、依赖是一种类与类之间弱耦合的关系,如下图用虚线箭头表示:
在五种关系中,依赖是耦合最小的一种,在类与类的代码中都不会增加属性,如下图:
a 在Animal类中,没有Water属性,那么Animal类怎么使用Water类呢?有三种方式
1 Water类是全局的,则Animal类可以调用它
2 Water类是Animal类的某个方法中的变量,则Animal类可以调用它。
Water类的生命期,它是当Animal类的方法被调用的时候,才被实例化。
持有Water类的是Animal的一个方法而不是Animal类
3 Water类是作为Animal类中某个方法的参数或者返回值时。
Water类被Animal类的一个方法持有。生命期随着方法的执行结束而结束。
3 关联用实线箭头表示,如下图:
如下代码:在类cloud属性中,添加了Climate
关联既有单向关联又有双向关联,上图中为单向关联,Cloud类成为源类,Climate类成为目标类,源类了解目标类的属性、成员、信息,但目标类不了解源类。
双向关联,有双向箭头,信息相互了解。
在各自代码中,都有对方类,作为自己的一个属性成员。
依赖和关联的区别:
a 从类的属性是否增加的角度看:
发生依赖关系的两个类都不会增加属性。其中的一个类作为另一个类的方法的参数或者返回值,或者是某个方法的变量而已。
发生关联关系的两个类,其中的一个类成为另一个类的属性,而属性是一种更为紧密的耦合,更为长久的持有关系。
b 从关系的生命期角度看:
依赖关系是仅当类的方法被调用时而产生,伴随着方法的结束而结束了。
关联关系是当类实例化的时候即产生,当类销毁的时候,关系结束。相比依赖讲,关联关系的生存期更长。
l 聚合和组合的区别:
我们大家都知道表面上他们的区别,聚合比组合关系弱一些,那么这个弱的关系如何在代码中体现呢?
区分的关键有两点:
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面为,大话设计中一个例子:两个类之间为聚合关系。
//工作经历类
class WorkExperience
{
private string workDate;
public string WorkDate
{
get { return workDate; }
set { workDate = value; }
}
private string company;
public string Company
{
get { return company; }
set { company = value; }
}
}
//简历代码
class Resume:ICloneable
{
private string name;
private string sex;
private string age;
//引用工作经历对象
private WorkExperience work;
public Resume(string name)
{
this.name = name;
//在“简历”类实例化时,同时实例化,“工作经历类”
work = new WorkExperience();
}
//设置个人信息
public void SetPersonInfo(string sex, string age)
{
this.sex=sex;
this.age=age;
}
//设置工作经历
public void SetWorkExperience(string workDate,string company )
{
//在调用此方法时,给对象的两个属性赋值
work.WorkDate = workDate;
work.Company = company;
}
public void Display()
{
Console.WriteLine("{0}{1}{2}",name,sex,age);
//显示时,显示“工作经历”的两个属性值
Console.WriteLine("工作经历:{0}{1}",work.WorkDate,work.Company);
}
public object Clone()
{
return (object)this.MemberwiseClone();
}
}
这两种关系的区别在于:
①构造函数不同
聚合类的构造函数中包含了另一个类作为参数。
雁群类(GooseGroup)的构造函数中要用到大雁(Goose)作为参数传递进来。大雁类(Goose)可以脱离雁群类而独立存在。
组合类的构造函数中包含了另一个类的实例化。
表明大雁类在实例化之前,一定要先实例化翅膀类(Wings),这两个类紧密的耦合在一起,同生共灭。翅膀类(Wings)是不可以脱离大雁类(Goose)而独立存在
②信息的封装性不同
在聚合关系中,客户端可以同时了解雁群类和大雁类,因为他们都是独立的
而在组合关系中,客户端只认识大雁类,根本就不知道翅膀类的存在,因为翅膀类被严密的封装在大雁类中。
在这里涉及到一个设计模式即CARP模式,合成、聚合复用原则,尽量使用合成、聚合,尽量不用使用类继承。继承是一种强耦合关系,父类变,子类就必须变。