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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章