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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值