設(shè)計模式需要用到面向?qū)ο蟮娜筇匦浴庋b、繼承、多態(tài)(同名函數(shù)具有不同的狀態(tài))
UML類圖 eg.—— 描述類之間的關(guān)系(設(shè)計程序之間畫類圖)
?+: public; #: protected; -: private; 下劃線: static
屬性名:類型(=默認值)
方法和變量分開-------
虛函數(shù)斜體,純虛函數(shù)在虛函數(shù)類型后=0,并且類名斜體
類與類之間的關(guān)系:
1. 繼承關(guān)系(空心三角形實線,箭頭指父類)
2. 關(guān)聯(lián)關(guān)系(單項關(guān)聯(lián)、雙向關(guān)聯(lián)、自關(guān)聯(lián) - 鏈表)用帶箭頭和不帶箭頭的實現(xiàn)
3. 聚合關(guān)系(整體與部分的關(guān)系,整體析構(gòu)部分不析構(gòu))空心菱形實線鏈接,指向整體
4. 組合關(guān)系(整體析構(gòu)部分析構(gòu))實心菱形實線鏈接
5. 依賴關(guān)系(使用關(guān)系)帶箭頭的虛線,指向被依賴方
類之間的關(guān)系強弱:繼承(泛化)>組合>聚合>關(guān)聯(lián)>依賴(類圖按類間最強關(guān)系就可)
設(shè)計模式三原則
單一職責(zé)原則(面向?qū)ο螅?/strong>
使得類的功能盡量單一,方便管理維護,避免類的臃腫。
開放封閉原則:
對于擴展是開放的,對于修改是封閉的,增加程序可維護性可擴展性。
依賴轉(zhuǎn)換原則:
高層模塊不應(yīng)該依賴低層模塊(應(yīng)用程序不直接調(diào)用API),兩個都應(yīng)該依賴抽象。
抽象不依賴細節(jié),細節(jié)應(yīng)該依賴抽象。(里氏代換原則)
單例模式和任務(wù)隊列(類的對象只能創(chuàng)建出一個)
一個項目中,全局范圍內(nèi),某個類的實例有且僅有一個,通過這個實例向其他模塊提供數(shù)據(jù)的全局訪問。(簡介訪問實現(xiàn)對于變量的保護)
將類的默認構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù)設(shè)為private,或者將兩個函數(shù)=delete;
使類無法在外面創(chuàng)建對象,只能通過類名訪問靜態(tài)屬性或者方法;
懶漢模式和餓漢模式
餓漢模式——定義類的時候創(chuàng)建單例對象(多線程下沒有線程安全問題)
// 餓漢模式
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete;
static A* get(){
return num;
}
print(){
cout<<"單例模式的唯一實例";
}
private:
A() = default; // 默認構(gòu)造
static A* num;
};
A* A::num = new A;
int main(){
A* a = A::get();
a->print();
return 0;
}
懶漢模式——什么時候使用單例對象再去創(chuàng)建實例(多線程下存在線程安全問題)
// 懶漢模式
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete;
static A* get(){
num = new A;
return num;
}
print(){
cout<<"單例模式的唯一實例";
}
private:
A() = default; // 默認構(gòu)造
static A* num;
};
A* A::num = nullptr;
int main(){
A* a = A::get();
a->print();
return 0;
}
懶漢模式的線程安全問題
可以通過雙重檢查鎖定解決懶漢模式的線程安全問題:1. 互斥鎖(導(dǎo)致效率低) 2. 實例創(chuàng)建判定
// 懶漢模式
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete;
static A* get(){ // first check
if(num==nullptr){
lk.lock();
if(num==nullptr)num = new A; // second check
lk.unlock();
}
return num;
}
print(){
cout<<"單例模式的唯一實例";
}
private:
A() = default; // 默認構(gòu)造
static A* num;
static mutex lk;
};
A* A::num = nullptr;
mutex A::lk;
int main(){
A* a = A::get();
a->print();
return 0;
}
通過原子變量(atomic - 底層控制機器指令執(zhí)行順序)解決雙重檢查鎖定的問題;放置底層的機器指令不按理想順序執(zhí)行
// 懶漢模式
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete;
static A* get(){ // first check
A* cur = task.load();
if(cur==nullptr){
lk.lock();
cur = task.load();
if(cur==nullptr){
cur = new A; // second check
task.store(cur);
}
lk.unlock();
}
return cur;
}
print(){
cout<<"單例模式的唯一實例";
}
private:
A() = default; // 默認構(gòu)造
static A* num;
static mutex lk;
static atomic<A*> task;
};
A* A::num = nullptr;
mutex A::lk;
atomic<A*> A::task;
int main(){
A* a = A::get();
a->print();
return 0;
}
使用靜態(tài)局部對象解決線程安全問題
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete;
static A* get(){ // first check
static A a;
return &a;
}
print(){
cout<<"單例模式的唯一實例";
}
private:
A() = default; // 默認構(gòu)造
};
int main(){
A* a = A::get();
a->print();
return 0;
}
并發(fā)執(zhí)行應(yīng)當(dāng)?shù)却兞客瓿沙跏蓟?/p>
總結(jié)
1. 餓漢模式不存在線程安全問題文章來源:http://www.zghlxwxcb.cn/news/detail-678150.html
2. 懶漢模式通過雙重檢查鎖定+原子變量或者靜態(tài)局部對象(簡單)可以解決線程安全問題? ? ? ?文章來源地址http://www.zghlxwxcb.cn/news/detail-678150.html
實踐(多線程模式下的任務(wù)模型)
#include <bits/stdc++.h>
using namespace std;
// 餓漢模式
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete;
static A* get(){
return num;
}
print(){
cout<<"單例模式的唯一實例";
}
bool isempty(){
lock_guard<mutex> locker(m_mutex);
return mis.empty();
}
void add_m(int node){
lock_guard<mutex> locker(m_mutex);
mis.push(node);
}
bool minus_m(){
lock_guard<mutex> locker(m_mutex);
if(mis.empty())return false;
else{
mis.pop();
}
return true;
}
int get_m(){
lock_guard<mutex> locker(m_mutex);
if(mis.empty())return -1;
return mis.front();
}
private:
A() = default; // 默認構(gòu)造
static A* num;
queue<int> mis;
mutex m_mutex;
};
A* A::num = new A;
int main(){
A *a = A::get();
// 生產(chǎn)者
thread t1([=](){
for(int i = 0 ; i<10 ; i++){
a->add_m(i+100);
cout<<"push data: "<<i+100<<" "<<"threadId: "<<this_thread::get_id()<<endl;
this_thread::sleep_for(chrono::milliseconds(500));
}
});
// 消費者
thread t2([=](){
this_thread::sleep_for(chrono::milliseconds(100));
while(!a->isempty()){
int cur = a->get_m();
cout<<"take data: "<<cur<<" "<<"threadId: "<<this_thread::get_id()<<endl;
a->minus_m();
this_thread::sleep_for(chrono::milliseconds(1000));
}
});
// 阻塞主線程
t1.join();
t2.join();
return 0;
}
到了這里,關(guān)于自學(xué)設(shè)計模式(類圖、設(shè)計原則、單例模式 - 餓漢/懶漢)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!