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——类图的主要内容,如果未能解决你的问题,请参考以下文章

UML类图详解

UML 类图口诀

UML类图

UML 类图常用表示方法.

UML类图

设计模式-UML类图的各符号含义(转)