类间关系.docx
《类间关系.docx》由会员分享,可在线阅读,更多相关《类间关系.docx(17页珍藏版)》请在冰豆网上搜索。
类间关系
在建立对象模型时,很容易把依赖、关联和聚集关系混淆。
当对象A和对象B之间存在依赖、关联或聚集/组合关系时,对象A都有可能调用对象B的方法,这是三种关系之间的相同之处,除此之外,它们有着不同的特征。
依赖关系:
对于两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间主要体现为依赖关系。
例如:
机器生产零件,充电电池通过充电器来充电,自行车通过打气筒来充气,人借助螺丝刀拧螺丝,人借用船过河,艺术家鉴赏艺术品,警察抓小偷,小猫钓鱼,学生读书,某人买车。
classB{...}
classA{...}
A:
:
Function1(B&b)//或A:
:
Function1(B*b)//或A:
:
Function1(Bb)
//或B*A:
:
Function1()//或B&A:
:
Function1()
//或intA:
:
Function1()
{B*pb=newB;/*...*/deletepb;}
//Car.h
classCCar
{
//Dosomething
};
//Person.h
#include"Car.h"
classCPerson
{
voidMoveFast(CCar&pCar);
};
人的快速移动需要有车的协助,但是这种依赖是比较弱的,就是人也可以不用车而用其他工具,与关联不同的是人不必拥有这辆车只要使用就行。
单向依赖例:
一只老鼠在苹果园中吃苹果,老鼠每吃一个苹果,就根据该苹果的所含能量增加一些体重。
结合上边给出的模型,设计老鼠和苹果类。
//苹果类:
classApple
{
public:
Apple(inte):
power(e){}
intEnergy()const{returnpower;}
private:
intpower;
};
//老鼠类
classMouse
{
public:
Mouse(intw):
weight(w){}
intWeight()const{returnweight;}
voidEat(Apple*one){weight+=one->Energy()*0.5;}
private:
intweight;
};
扩展1:
classParent;
classA{
public:
virtual~A();
voidFunc(Parent*p);
};
扩展2:
classHuman{
public:
virtual~Human(){}
virtualvoidRead(Book*);
};
classStudent:
publicHuman{}
classRobot:
publicHuman{}
classBook{
public:
virtual~Book(){}
//…..
};
classNovel:
publicBook{}
classCartoon:
publicBook{}
自身依赖例:
一个游戏中有很多怪物(Monster),怪物之间可能要发生战斗(fight),每场战斗都是一个怪物与另一怪物之间的一对一战斗。
每个怪物都有自己的速度(Speed)、生命值(hitpoint)、攻击力值(damage)和防御力值(defense);战斗时,两个怪物依次攻击对方,即怪物a首先攻击怪物b,然后轮到怪物b攻击怪物a,之后,怪物a再次攻击怪物b,…,直到一方生命值为0;战斗时,由速度快的一方首先发起攻击;若速度一样,比较生命值,由高者首先攻击;若生命值也相等,比较攻击力,由高者首先攻击;若攻击力还相等,比较防御力,由高者首先攻击;若四项都相等,则选择任一方首先攻击;怪物A攻击怪物B时,会给怪物B造成伤害,使得怪物B的生命值降低,降低值为:
2*A的攻击力-B的防御力,最小为1。
请根据你对上述描述的理解,定义并实现怪物类Monster,成员的设计可以任意,但要求该类至少有一个成员函数fight,用来描述与另外一个怪物进行战斗的过程。
不必考虑怪物的生命值减少至0后如何处理。
classMonster{
public:
Monster(intspd,inthp,intdam,intdef);
boolFight(Monster&other);
private:
intAttacked(Monster&other)const;
boolPriorTo(constMonster&other)const;
private:
intspeed;
inthitpoint;
intdamage;
intdefense;
};
Monster:
:
Monster(intspd,inthit,intdam,intdef):
speed(spd),hitpoint(hit),damage(dam),defense(def)
{
}
boolMonster:
:
Fight(Monster&other)
{
if(PriorTo(other))
if(Attacked(other)==0)
returntrue;
while(true){
if(other.Attacked(*this)==0)
returnfalse;
if(Attacked(other)==0)
returntrue;
}
}
intMonster:
:
Attacked(Monster&other)const
{
intharm=damage*2-other.defense;
if(harm<1)
harm=1;
other.hitpoint-=harm;
if(other.hitpoint<0)
other.hitpoint=0;
returnother.hitpoint;
}
boolMonster:
:
PriorTo(constMonster&other)const
{
if(speed!
=other.speed)
returnspeed>other.speed;
if(hitpoint!
=other.hitpoint)
returnhitpoint>other.hitpoint;
if(damage!
=other.damage)
returndamage>other.damage;
if(defense!
=other.defense)
returndefense>other.defense;
returntrue;
}
intmain()
{
Monstera(10,200,7,8);
Monsterb(10,150,8,7);//改成(10,180,8,7)则战斗失败
if(a.Fight(b))
cout<<"AWin!
"<else
cout<<"ALose!
"<return0;
}
扩展1:
例如,作业8,怪兽
扩展2:
例:
一个荒岛上生活着各种动物,它们一直和平相处。
直到有一天,一种新猛兽的来到改变了一切,它们不但袭击其他动物,甚至也吃同类,……
双向依赖例:
classPolice
{
public:
Police(){totalAward=0;}
voidCatch(Person*p);
intGetAward()const{returntotalAward;}
private:
inttotalAward;
};
classPerson
{
public:
virtual~Person(){}
virtualvoidBeCatched(Police*cop){}
};
关联关系:
对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时,这两个对象之间为关联关系。
例如:
客户和订单(1:
N),公司和员工(1:
N),主人和汽车(1:
N),师傅和徒弟(1:
N),丈夫和妻子(1:
1),飞机和航班(1:
N),学生和课程(N:
N)。
classB{...}
classA{B*b;.....}
A:
:
afun(){b->bfun();}
关联关系是一种拥有的关系,可以分为单向关联,自身关联和双向关联。
单向关联是指只有某一方拥有另一方的引用,这样只有拥有对方者可以调用对方的公共属性和方法。
如下面代码:
//Husband.h
classCHusband
{
public:
intnMoney;
voidGoShopping();
};
//Wife.h
#include"Husband.h"
classCWife
{
public:
CHusband*pHuband;
};
上面代码中妻子拥有丈夫,可以使用对方的属性,比如钱,可以让对方做能做的事,比如去买东西。
单向关联例1:
游戏中的英雄有各自的魅力值、声望值、攻击力、防御力、法力等,每个英雄可以最多带5个宝物,每种宝物有特有提升英雄某种能力的效果。
游戏中假设共有6种宝物(暂时用1,2,3,....6代表,1提升魅力2点,2提升声望3点,3提升攻击力1点,...),英雄这个类需要有功能:
取得当前状态下的各种能力值,在指定位置中携带指定宝物,丢弃指定位置中的宝物等。
constintABLITTYCOUNT=5;//5种属性值
enumABLITY{CHARM=0,REPUTE,ATTACK,DEFENSE,POWER};
enumGOODS{NONE=0,G1,G2,G3,G4,G5,G6};//6种宝物
constintBAGCOUNT=5;//5个宝物袋
classHero
{
public:
Hero(intcha,intrep,intatt,intdef,intpow);
voidAddGood(intbagID,GOODSgoods);
voidRemoveGood(intbagID);
intCurAblity(ABLITYwhich)const{returncurAblities[which];}
private:
voidRecaculateAblities();
private:
//魅力值、声望值、攻击力、防御力、法力
intrawAblities[ABLITTYCOUNT];
intcurAblities[ABLITTYCOUNT];
//宝物袋
GOODS*bags[BAGCOUNT];
};
单向关联例2:
学生管理程序中学生和宿舍。
每个学生的信息除了包括姓名、学号等之外,还要有宿舍信息。
宿舍信息包括几号楼,第几层,几号房间,以及住了哪几个学生等信息。
classStudent
{
public:
Student(Dorm*aDorm):
mpDorm(aDorm){}
~Student(){}
intDormFloor()const{returnmpDorm->Floor();}
//….
private:
Dorm*mpDorm;
};
扩展:
classParent;
classA{
public:
virtual~A();
voidFunc();
protected:
Parent*p;
};
自身关联是指拥有一个自身的引用。
如下面代码:
//SingleMan.h
classCSingleMan
{
public:
CSingleMan*pSingleMan;
};
双向关联是指双方都拥有对方的引用,都可以调用对方的公共属性和方法。
//Husband.h
classCWife;
classCHusband
{
public:
CWife*pWife;
};
//Wife.h
#include"Husband.h"
classCWife
{
public:
CHusband*pHuband;
};
上面代码中丈夫和妻子是比较公平的关系,都可以使用对方公共的属性。
聚集关系:
当对象B被加入到对象A中,成为对象A的组成部分时,对象A和对象B之间为聚集关系。
聚集是关联关系的一种特例。
聚集指的是整体与部分之间的关系,体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;
例如:
自行车和车把、响铃、轮胎,汽车和引擎、轮胎、刹车装置,电脑和主板、CPU、内存、硬盘,航母编队和航母、驱护舰艇、舰载机、潜艇,课题组和科研人员。
classB{...}
classA{B*b;.....}
//Car.h
#include"Tyre.h"
classCCar
{
public:
CTyre*cTyre[4];
};
//Tyre.h
classCTyre
{
//Dosomething
};
聚集例:
学生宿舍管理程序中宿舍和学生。
宿舍有多个学生,宿舍建立时,可以指定,也可不指定对应的多个学生,并且以后可以随时增删学生。
classDorm{
public:
Dorm(Student*s[],intcount):
maxCount(count){
mStudents=newStudent*[maxCount];
for(inti=0;imStudents[i]=s[i];
}
~Dorm(){delete[]mStudents;}
voidAddStudent(Student*s,intindex){
if(mStudents[index]==NULL))
mStudents[index]=s;
}
voidRemoveStudent(intindex){
mStudents[index]=NULL;
}
private:
intmaxCount;
Student**mStudents;
};
扩展1:
classParent;
classA{
public:
virtual~A();
voidFunc();
protected:
Parent*p[5];
};
例如:
作业8,盒子放水果
扩展2:
扩展3:
例:
装饰,策略
例:
适配器(Adapter)
扩展4:
扩展5:
例:
在制作绘图程序时,需要绘制各种图形元素,包括矩形、椭圆等。
现需要增加一种图形元素—Grid,每个Grid本身就是一个矩形,但其文本内容一定为空,同时一个Grid还包含多个矩形,矩形个数由创建Grid时的参数指定,示例如图。
请定义并实现类Grid。
classShape{
public:
virtual~Shape(){}
virtualvoidDraw()=0;
};
ClassEllipse:
publicShape{
public:
virtual~Ellipse(){}
virtualvoidDraw(){/*略*/}
};
classRect:
publicShape{
public:
Rect(constchar*text){/*略*/}
virtual~Rect(){}
virtualvoidDraw(){/*略*/}
};
classGrid:
publicRect{
public:
Grid(intn):
Rect(NULL),count(n)
{
prects=newShape*[count];
for(inti=0;i{
prects[i]=newRect(NULL);
}
}
voidDraw()
{
for(inti=0;iprects[i]->Draw();
}
~Grid()
{
for(inti=0;i{
deleteprects[i];
}
delete[]prects;
}
private:
intcount;
Shape**prects;
};
组合关系:
组合也是关联关系的一种特例,体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合;同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束。
整体类负责部分类对象的生存与消亡。
例如:
公司和部门,人和大脑、四肢,窗口和标题栏、菜单栏、状态栏。
classB{...}
classA{Bb;...}
或
classA{
public:
A():
pb(newB){}
~A(){deletepb;}
private:
B*pb;...}
//Company.h
#include"Department.h"
classCCompany
{
public:
CDepartmentcDepartment[N];
};
//Department.h
classCDepartment
{
//Dosomething
};
在代码层面,关联、聚集和组合是一致的,只能从语义级别来区分三者;
几种关系所表现的强弱程度依次为:
组合>聚合>关联>依赖;
泛化关系
classB{}
classA:
publicB{}
//Animal.h
classCAnimal
{
public:
//implement
virtualvoidEatSomething()
{
//Dosomething
}
};
//Tiger.h
#include"Animal.h"
classCTiger:
publicCAnimal
{
//Dosomething
};
实现关系
泛化和实现的区别就在于子类是否继承了父类的实现,如有继承则关系为泛化,反之为实现.
//Animal.h
classCAnimal
{
public:
//interface
virtualvoidEatSomething()=0;
};
//Tiger.h
#include"Animal.h"
classCTiger:
publicCAnimal
{
//Dosomething
};