UML学习01——类图
Posted yfyzwr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UML学习01——类图相关的知识,希望对你有一定的参考价值。
本文参考文章:
类图(Class Diagram)是面向对象系统建模中最常用和最重要的图,是定义其它图的基础。类图主要是用来描述系统中的类、接口以及它们之间的静态结构和关系的一种静态模型。
画类图的时候,理清类和类之间的关系是重点。类与类之间的关系有多种:
- 泛化(Generalization)
- 实现(Realization)
- 关联(Association)
- 聚合(Aggregation)
- 组合(Composition)
- 依赖(Dependency)
其中,关联关系又包括一般关联、聚合关系、组合关系。
下面结合实例来说明,分别理解这些不同的关系。
泛化(Generalization)
泛化是一种继承关系,它指出子类如何特化父类的所有特征和行为(例如老虎类是动物类的子类)。
- 关系说明:表示is-a的关系,是对象之间耦合度最大的一种关系,子类继承父类的所有细节。
- 代码体现:直接使用语言本身的继承语法表达。
- 箭头指向:使用带三角箭头的实线表示,箭头从子类指向父类。
实现(Realization)
实现是一种类与接口的关系,表示类是接口所有特征和行为的实现(例如铅笔刷是刷子接口的实现类)。
- 关系说明:如果将接口看作特殊定义的类,就类似于is-a的关系,具体类实现接口的所有细节。
- 代码体现:直接使用语言本身的实现语法表达。
- 箭头指向:使用带三角箭头的虚线,箭头从实现类指向接口。
关联(Association)
关联是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一类对象与另一类对象之间有联系(如汽车和轮胎、师傅和徒弟、班级和学生等),并没有整体与部分的关系。
- 关系说明:关联是对象之间的一种结构化关系,这种关系通常使用类的属性表达。
- 代码实现:通常将一个类的对象作为另一个类的成员变量。
- 箭头指向:使用带箭头的实线表示,箭头从使用类指向被关联的类。关联可以是单向的、双向的、自关联的、多重关联的,其中双向的关联可以有两个箭头或者没有箭头。
聚合(Aggregation)
聚合表示整体与部分的关系。在聚合关系中,部分对象是整体对象的一部分,但是部分对象可以脱离整体对象而独立存在。例如汽车发动机(Engine)是汽车(Car)的部分,但是汽车发动机可以独立存在,因此汽车和发动机就是聚合关系。
- 关系说明:表示has-a的关系,是一种不稳定的包含关系,关联性较强于一般关联,有整体与局部的关系,并且没有了整体,而局部也可单独存在。
- 代码实现:聚合关系是关联关系的一种,是强的关联关系,关联和聚合在语法上无法区分,必须考察具体的逻辑关系。通常将部分类的对象作为整体类的成员变量,部分对象通常作为构造方法、Setter方法或业务方法的参数注入到整体对象中。
- 箭头指向:使用带空心菱形的实线,菱形指向整体对象。
组合(Composition)
组合也表示整体和部分的关系。在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不复存在,部分对象与整体对象之间具有同生共死的关系。例如人的头(Head)与嘴巴(Mouth), 嘴巴是头的组成部分,但是如果头没了,嘴巴也就没了,因此头和嘴巴就是组合关系。
- 关系说明:表示contains-a的关系,是一种强烈的包含关系。组合类负责被组合类的生命周期,是一种更强的聚合关系。部分不能脱离整体存在。
- 代码实现:组合关系是关联关系的一种,是强的关联关系,关联和组合在语法上无法区分,必须考察具体的逻辑关系。通常将部分类的对象作为整体类的成员变量,然后通常在整体类的构造方法中直接实例化部分类对象。
- 箭头指向:使用带实心菱形的实线,菱形指向整体。
依赖(Dependency)
依赖是对象之间最弱的一种关联方式,是临时性的关联。
- 关系说明:依赖关系是一种使用关系,一个类调用被依赖类中的某些方法而得以完成这个类的一些职责,而被依赖事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系。
- 代码实现:通常将被依赖类作为依赖类的方法的局部变量、方法的形参、方法中调用被依赖类的静态方法。
- 箭头指向:使用带箭头的虚线,指向被依赖者。
综上所述,各种类图关系之间,彼此的强弱关系为:泛化 = 实现> 组合> 聚合> 关联> 依赖。
#include "blocking_queue.h"
template <typename T>
blocking_queue<T>::blocking_queue(const int max_size)
this->m_max_size = max_size;
this->m_task_size = 0;
this->m_unfinished_tasks = 0;
this->m_deque = new deque<T>(max_size);
this->m_mutex = new pthread_mutex_t;
this->m_not_empty = new pthread_cond_t;
this->m_not_full = new pthread_cond_t;
this->m_all_tasks_done = new pthread_cond_t;
pthread_mutex_init(this->m_mutex, NULL);
pthread_cond_init(this->m_not_empty, NULL);
pthread_cond_init(this->m_not_full, NULL);
pthread_cond_init(this->m_all_tasks_done, NULL);
template <typename T>
blocking_queue<T>::~blocking_queue()
if(this->m_deque != NULL)
delete this->m_deque;
pthread_mutex_destroy(this->m_mutex);
pthread_cond_destroy(this->m_not_empty);
pthread_cond_destroy(this->m_not_full);
pthread_cond_destroy(this->m_all_tasks_done);
delete this->m_mutex;
delete this->m_not_empty;
delete this->m_not_full;
delete this->m_all_tasks_done;
template <typename T>
bool blocking_queue<T>::empty()
bool result = false;
pthread_mutex_lock(this->m_mutex);
result = this->m_task_size == 0;
pthread_mutex_unlock(this->m_mutex);
return result;
template <typename T>
bool blocking_queue<T>::full()
bool result = false;
pthread_mutex_lock(this->m_mutex);
result = this->m_task_size == this->m_max_size;
pthread_mutex_unlock(this->m_mutex);
return result;
template <typename T>
int blocking_queue<T>::clear()
pthread_mutex_lock(this->m_mutex);
this->m_task_size = 0;
this->m_unfinished_tasks = 0;
this->m_deque->clear();
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
template <typename T>
int blocking_queue<T>::size()
int iResult = 0;
pthread_mutex_lock(this->m_mutex);
iResult = (int)this->m_deque->size();
pthread_mutex_unlock(this->m_mutex);
return iResult;
template <typename T>
int blocking_queue<T>::put(const T &task, const bool block, const int timeout)
struct timespec ts = 0, 0;
struct timeval now = 0, 0;
gettimeofday(&now, NULL);
ts.tv_sec = now.tv_sec + timeout;
ts.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(this->m_mutex);
if(block == false)
if(this->m_task_size == this->m_max_size)
pthread_mutex_unlock(this->m_mutex);
return ERROR_FULL;
else if(timeout < 0)
while(this->m_task_size == this->m_max_size)
pthread_cond_wait(this->m_not_full, this->m_mutex);
else
while(this->m_task_size == this->m_max_size)
int iResult = SUCCESS;
iResult = pthread_cond_timedwait(this->m_not_full, this->m_mutex, &ts);
if(iResult == ETIMEDOUT)
pthread_mutex_unlock(this->m_mutex);
return ERROR_TIMEOUT;
else if(iResult != SUCCESS)
pthread_mutex_unlock(this->m_mutex);
return ERROR_OTHER;
this->m_deque->push_back(task);
this->m_task_size += 1;
this->m_unfinished_tasks += 1;
pthread_cond_signal(this->m_not_empty);
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
template <typename T>
int blocking_queue<T>::put_nowait(T& task)
return put(task, false);
template <typename T>
int blocking_queue<T>::get(T& task, const bool block, const int timeout)
struct timespec ts = 0, 0;
struct timeval now = 0, 0;
gettimeofday(&now, NULL);
ts.tv_sec = now.tv_sec + timeout;
ts.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(this->m_mutex);
if(block == false)
if(this->m_task_size == 0)
pthread_mutex_unlock(this->m_mutex);
return ERROR_EMPTY;
else if(timeout < 0)
while(this->m_task_size == 0)
pthread_cond_wait(this->m_not_empty, this->m_mutex);
else
while(this->m_task_size == 0)
int iResult = SUCCESS;
iResult = pthread_cond_timedwait(this->m_not_empty, this->m_mutex, &ts);
if(iResult == ETIMEDOUT)
pthread_mutex_unlock(this->m_mutex);
return ERROR_TIMEOUT;
else if(iResult != SUCCESS)
pthread_mutex_unlock(this->m_mutex);
return ERROR_OTHER;
memcpy(&task, &this->m_deque->front(), sizeof(T));
this->m_deque->pop_front();
this->m_task_size -= 1;
pthread_cond_signal(this->m_not_full);
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
template <typename T>
int blocking_queue<T>::get_nowait(T& task)
return get(task, false);
template <typename T>
int blocking_queue<T>::task_done()
int unfinished = 0;
pthread_mutex_lock(this->m_mutex);
unfinished = this->m_unfinished_tasks - 1;
if(unfinished < 0)
pthread_mutex_unlock(this->m_mutex);
return ERROR_VALUE;
else if(unfinished == 0)
pthread_cond_broadcast(this->m_all_tasks_done);
this->m_unfinished_tasks = unfinished;
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
template <typename T>
int blocking_queue<T>::join()
pthread_mutex_lock(this->m_mutex);
while(this->m_unfinished_tasks != 0)
pthread_cond_wait(this->m_all_tasks_done, this->m_mutex);
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
#ifndef _BLOCKING_QUEUE_H
#define _BLOCKING_QUEUE_H
#include <iostream>
#include <deque>
#include <pthread.h>
#include <sys/time.h>
#define SUCCESS 0
#define ERROR_EMPTY 1
#define ERROR_FULL 2
#define ERROR_TIMEOUT 3
#define ERROR_ARGUMENT 4 // 寮傚父鐨勫弬鏁?
#define ERROR_VALUE 5 // 鍙橀噺鐨勫彇鍊煎紓甯?
#define ERROR_OTHER 9999 // 鍏朵粬鏃犻渶鍏崇郴鐨勯敊璇?
using namespace std;
template <typename T>
class blocking_queue
public:
blocking_queue(const int max_size)
this->m_max_size = max_size;
this->m_task_size = 0;
this->m_unfinished_tasks = 0;
this->m_deque = new deque<T>(max_size);
this->m_mutex = new pthread_mutex_t;
this->m_not_empty = new pthread_cond_t;
this->m_not_full = new pthread_cond_t;
this->m_all_tasks_done = new pthread_cond_t;
pthread_mutex_init(this->m_mutex, NULL);
pthread_cond_init(this->m_not_empty, NULL);
pthread_cond_init(this->m_not_full, NULL);
pthread_cond_init(this->m_all_tasks_done, NULL);
~blocking_queue()
if(this->m_deque != NULL)
delete this->m_deque;
pthread_mutex_destroy(this->m_mutex);
pthread_cond_destroy(this->m_not_empty);
pthread_cond_destroy(this->m_not_full);
pthread_cond_destroy(this->m_all_tasks_done);
delete this->m_mutex;
delete this->m_not_empty;
delete this->m_not_full;
delete this->m_all_tasks_done;
bool empty()
bool result = false;
pthread_mutex_lock(this->m_mutex);
result = this->m_task_size == 0;
pthread_mutex_unlock(this->m_mutex);
return result;
bool full()
bool result = false;
pthread_mutex_lock(this->m_mutex);
result = this->m_task_size == this->m_max_size;
pthread_mutex_unlock(this->m_mutex);
return result;
int clear()
pthread_mutex_lock(this->m_mutex);
this->m_task_size = 0;
this->m_unfinished_tasks = 0;
this->m_deque->clear();
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
int size()
int iResult = 0;
pthread_mutex_lock(this->m_mutex);
iResult = (int)this->m_deque->size();
pthread_mutex_unlock(this->m_mutex);
return iResult;
int put(const T& task, const bool block = true, const int timeout = -1)
struct timespec ts = 0, 0;
struct timeval now = 0, 0;
gettimeofday(&now, NULL);
ts.tv_sec = now.tv_sec + timeout;
ts.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(this->m_mutex);
if(block == false)
if(this->m_task_size == this->m_max_size)
pthread_mutex_unlock(this->m_mutex);
return ERROR_FULL;
else if(timeout < 0)
while(this->m_task_size == this->m_max_size)
pthread_cond_wait(this->m_not_full, this->m_mutex);
else
while(this->m_task_size == this->m_max_size)
int iResult = SUCCESS;
iResult = pthread_cond_timedwait(this->m_not_full, this->m_mutex, &ts);
if(iResult == ETIMEDOUT)
pthread_mutex_unlock(this->m_mutex);
return ERROR_TIMEOUT;
else if(iResult != SUCCESS)
pthread_mutex_unlock(this->m_mutex);
return ERROR_OTHER;
this->m_deque->push_back(task);
this->m_task_size += 1;
this->m_unfinished_tasks += 1;
pthread_cond_signal(this->m_not_empty);
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
int put_nowait(T& task)
return put(task, false);
int get(T& task, const bool block = true, const int timeout = -1)
struct timespec ts = 0, 0;
struct timeval now = 0, 0;
gettimeofday(&now, NULL);
ts.tv_sec = now.tv_sec + timeout;
ts.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(this->m_mutex);
if(block == false)
if(this->m_task_size == 0)
pthread_mutex_unlock(this->m_mutex);
return ERROR_EMPTY;
else if(timeout < 0)
while(this->m_task_size == 0)
pthread_cond_wait(this->m_not_empty, this->m_mutex);
else
while(this->m_task_size == 0)
int iResult = SUCCESS;
iResult = pthread_cond_timedwait(this->m_not_empty, this->m_mutex, &ts);
if(iResult == ETIMEDOUT)
pthread_mutex_unlock(this->m_mutex);
return ERROR_TIMEOUT;
else if(iResult != SUCCESS)
pthread_mutex_unlock(this->m_mutex);
return ERROR_OTHER;
memcpy(&task, &this->m_deque->front(), sizeof(T));
this->m_deque->pop_front();
this->m_task_size -= 1;
pthread_cond_signal(this->m_not_full);
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
int get_nowait(T& task)
return get(task, false);
int task_done()
int unfinished = 0;
pthread_mutex_lock(this->m_mutex);
unfinished = this->m_unfinished_tasks - 1;
if(unfinished < 0)
pthread_mutex_unlock(this->m_mutex);
return ERROR_VALUE;
else if(unfinished == 0)
pthread_cond_broadcast(this->m_all_tasks_done);
this->m_unfinished_tasks = unfinished;
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
int join()
pthread_mutex_lock(this->m_mutex);
while(this->m_unfinished_tasks != 0)
pthread_cond_wait(this->m_all_tasks_done, this->m_mutex);
pthread_mutex_unlock(this->m_mutex);
return SUCCESS;
private:
deque<T>* m_deque;
int m_max_size;
int m_task_size;
int m_unfinished_tasks;
pthread_mutex_t* m_mutex;
pthread_cond_t* m_not_empty;
pthread_cond_t* m_not_full;
pthread_cond_t* m_all_tasks_done;
;
#endif //_BLOCKING_QUEUE_H
#include <unistd.h>
#include "blocking_queue.h"
using namespace std;
void* customer(void* arg)
int task = -1;
blocking_queue<int>* bq = (blocking_queue<int>*)arg;
for(int i = 0; i < 100; ++i)
cout << "customer get : " << bq->get(task) << endl;
usleep(100);
void* producer(void* arg)
blocking_queue<int>* bq = (blocking_queue<int>*)arg;
for(int i = 0; i < 1000; ++i)
bq->put(i);
cout << "producer put :" << i << endl;
int main(int argc, char** argv)
pthread_t tid[2];
blocking_queue<int>* bq = new blocking_queue<int>(500);
pthread_create(tid, NULL, producer, (void*)bq);
pthread_create(tid+1, NULL, customer, (void*)bq);
pthread_join(*tid, NULL);
pthread_join(*(tid+1), NULL);
cout << "the number of bq is : " << bq->size() << endl;
以上是关于UML学习01——类图的主要内容,如果未能解决你的问题,请参考以下文章