您的位置:首页 > 编程语言

模块化C代码与UML对象模型之间的映射(3)——UML关系

2011-08-17 21:16 615 查看
下图是从StarUML工具界面截下来的,从上往下依次表示UML的关系:关联、单向关联、聚合、组合、泛化、依赖和实现。



图3 UML关系集

3.1 关联、聚合、组合

关联(association)是一种结构关系,它指明一个事物的对象与另一个事物的对象间的联系。聚合和组合是更强的关联,表示整体和部分的关系。

聚合的整体不负责部分的生命期,组合的整体负责部分的生命期。关联关系需根据实际场景来识别,例如军队和士兵的关系一般可理解为聚合,士兵退役了就和军队脱离聚合关系了。但是,如果是打仗时,士兵们必须生死与共,军队没了则士兵命也没了,则可理解为组合。

UML示例:



图3-1 关联、聚合、组合
C代码示例:

//A关联/聚合/组合了B
struct A{
struct B *b;
void (*Create)(B *b);  //方式1
};

struct A{
struct B *b;
void (*SetB)( B *b);   //方式2,单B
};

struct A{
struct B *bset
;
void (*RegisterB)(B *b); //方式3,B集
};

3.3 泛化

泛化(generalization)是一种特殊/一般的关系。也可以看作是常说的继承关系。

下面举一个用C语言实现继承的一个经典例子,从Linux内核源码中拷贝过来的。

UML示例:



图3-2 继承(泛化)

C代码示例(删节版):

struct kobject {
const char         *name;
struct kobject         *parent;
};

struct cdev {
struct kobject kobj;  //继承kobject
const struct file_operations *ops;
dev_t dev;
unsigned int count;
};

struct scullc_dev {
void **data;
struct scullc_dev *next;
struct cdev cdev;  //继承cdev
};


注意:继承不是定义结构体指针,而是定义结构体。

3.2 依赖

依赖(dependency)是两个事物之间的语义关系,其中一个事物(独立事物)发生变化,会影响到另一个事物(依赖事物)的语义。最常用的依赖关系是一个类的构造函数中用到另一个类的定义。

UML示例:

由于类的客户要依靠接口实现类的操作,所以我们把与接口的交互建模为一种依赖关系



图 3-3 依赖

C代码示例:

//方式1
void A_Method(struct A *a)
{
B_Method();  //B是实用类(即全局的实例),这种依赖方式在我们系统中最最多
}

//方式2
void A_Method(struct A *a, const struct B *b); //B作为参数被传递

//方式3
void A_Method(struct A *a)
{
struct B *b = B_Create();    //B在A的方法中实例化
}


3.4 实现

实现(realization)是类元之间的语义关系,其中的一个类元指定了由另一个类元保证执行的契约。

下面再拿Linux设备驱动做例子。scullc_dev类实现文件操作接口file_operations。

UML示例:



图3-4 实现

C代码示例:

//实现接口函数

int scullc_open (struct inode *inode, struct file *filp)
{
struct scullc_dev *dev; /* device information */

/*  Find the device */
dev = container_of(inode->i_cdev, struct scullc_dev, cdev);

/* ...*/

/* and use filp->private_data to point to the device data */

filp->private_data = dev;

return 0;          /* success */
}

ssize_t scullc_read (struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
struct scullc_dev *dev = filp->private_data; /* the first listitem */
struct scullc_dev *dptr;
int quantum = dev->quantum;
/* ... */

return retval;
}

//…

//文件操作接口实例

struct file_operations scullc_fops = {
.owner =     THIS_MODULE,
.llseek =    scullc_llseek,
.read =      scullc_read,
.write =     scullc_write,
.ioctl =     scullc_ioctl,
.open =       scullc_open,
.release =   scullc_release,
};

//
static void scullc_setup_cdev(struct scullc_dev *dev, int index)
{
int err, devno = MKDEV(scullc_major, index);

cdev_init(&dev->cdev, &scullc_fops); //注册接口
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scullc_fops;
err = cdev_add (&dev->cdev, devno, 1);

/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: