1. 程式人生 > >【設計模式】概述

【設計模式】概述

前言

一、設計模式概述

如果把修習軟體開發當作練武功修煉的話,那麼可以分為招式和內功

在這裡插入圖片描述
每一位軟體開發人員也都希望成為一名兼具淋漓招式和深厚內功的“上乘”,軟體開發工程師,二對設計模式的學習與領悟會讓你“內功”大增,再結合你日益純熟的“招式”,你的軟體開發“功力”一定會有一個新的境界,
在這裡插入圖片描述

1.1:設計模式之父:

在這裡插入圖片描述在這裡插入圖片描述

  • 綜上:

設計模式定義設計模式是在特定環境下人們解決某類重複出現的問題的一套成功有效的解決方案.

1.2: 軟體設計模式

設計模式由GoF四人組引入軟體工程領域,這就是軟體設計模式的誕生,軟體模式是將模式的一般概念應用軟體開發領域,即軟體開發的總指導思路與參照樣板,軟體模式並非僅限於設計模式,還包括架構模式,分析模式,和過程模式等。

軟體模式與具體的應用領域無關,也就是說無論你從事的是移動還是桌面開發,還是嵌入式,都可以使用軟體模式,無論使用那種面嚮物件語言都需要了解軟體設計模式。

軟體設計模式的概念是一套被反覆使用、多數人知曉的、經過分類編目的,程式碼設計經驗的總結,使用設計模式是為了可重用性程式碼,讓程式碼更容易被他人理解並且保持程式碼的可靠性。總之,在一定環境下,用固定套路解決問題。

1.3:軟體設計模式的種類

GoF提出的模式有23個,總包括:
建立型模式(6):如何建立物件
結構型模式(7):如何實現類和物件的組合
行為型模式(11):類或物件怎樣互動以及怎樣分配職責

當然,這23之外有一個“簡單工廠模式”,不屬於GoF23中設計模式,但大部分設計模式書籍都會對它進行介紹。
設計模式種類=GoF種類+“簡單工廠模式” = 24種

1.4:軟體設計模式作用

高階的講,作用大了去了,對於初學者,學習設計模式有助於更深一次理解面向物件,讓你知道:
如何將程式碼分散在不同類中
為什麼有介面
何謂針對抽象程式設計
何時不應該使用繼承
如何不修改原始碼增加新功能
更好的閱讀和理解現有庫和其他系統中的原始碼

學習設計模式讓你早點脫離“菜鳥期”!

1.5如何學好設計模式

學習基礎:多型【繼承,虛擬函式重寫,父類指標會引用指向子類物件】
初學者:積極累積案例,不能硬背
初級開發者:多思考,梳理,總結,尊重事物的規律,注意臨界點突破
中級開發者:合適的開發環境,尋找合適的設計模式來解決問題,多運用,對經典組合設計模式的大量,自由的運用,不斷的追求

1.6設計模式總瀏覽表
在這裡插入圖片描述
在這裡插入圖片描述

二、面向物件設計原則

對於面向物件軟體系統而言,在支援可維護性的同時,提高系統的可複用性是一個至關重要的問題,如何同時提高一個系統的可維護性和可複用性是面向物件以設計原則為基礎的,每一個原則都蘊含一些面性物件設計的思想,可以從不同角度提升一個軟體結構的設計水平

面向物件設計原則為支援可維護性可複用性二誕生,這些原則蘊含在很多設計模式中,他們是從許多設計方案中總結出來的指導性原則,面向物件設計原則也是我們用於評價一個設計模式的重要性指標之一
原則目的:
高內聚:目標明確單一,一個main只幹一件事,出了問題自行修改main,
低耦合,模組儘量少的跟其他模組互動,否則出了問題很難維護

1.1:單一職責原則

類的職責單一,對外只提供一個工能,而引起類變化的原因都應該只有一個

在這裡插入圖片描述

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <Windows.h>
using namespace std;
/*如果多人修改hi出問題
class Cloths
{
public:
	void Shopping()
	{
		cout << "休閒服裝" << endl;
	}
	void working()
	{
		cout << "正式服裝" << endl;
	}
};
 */


//改進
class Clothwork
{
public:
	void style()
	{
		cout << "正式服裝"<< endl;
	}
};
class Clothshopp
{
public:
	void style()
	{
		cout << "休閒服裝" << endl;
	}
};
int main()
{
	/*Cloths c1;
	c1.Shopping();

	c1.working();
	*/
	Clothshopp c2;
	c2.style();

	Clothwork c3;
	c3.style();
	system("pause");
	return 0;
}
//修改一個方法,會影響到其他方法,違反單一職責原則,應該將其分離出來

1.2:開閉原則(只允許增加,不允許修改)

類的改動是通過增加程式碼進行的,而不是修改原始碼

在這裡插入圖片描述

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;
/*
class bank
{
public:
	void save()
	{
		cout << "存款"<<endl;
	}
	void pay()
	{
		cout << "支付"<<endl;
	}
	void transfer()
	{
		cout << "轉賬"<<endl;
	}

	//新增一個行業務
	void jijin()
	{
		cout << "基金"<< endl;
	}	 寫完不能寫加入,違反單一原則,如果新加入工能有問題,系統就崩了
};	 */

//抽象 業務員類
class abstractbank
{
public:
	virtual void work() = 0; //抽象類介面

};
//存款
class save :public abstractbank
{
public:
	virtual void work()
	{
		cout << "存款"<< endl;
	}

};
//支付
class pay :public abstractbank
{
public:
	virtual void work()
	{
		cout <<"支付" << endl;
	}

};
//轉賬
class transfer :public abstractbank
{
public:
	virtual void work()
	{
		cout << "轉賬"<< endl;
	}

};

//新增基金
class add : public abstractbank
{
public:
	virtual void work()
	{
		cout << "基金" << endl;
	}
	
};
int main()
{
	abstractbank *sb = new save;
	sb->work();
	delete sb;

	abstractbank *sb = new pay;
	sb->work();
	delete sb;
	
	system("pause");
	return 0;
}
//改進後,新加功能不會影響原有功能

1.3:里氏代換原則

任何抽象類出現的地方都可以用它的實現類進行替換,實際就是虛擬機制,語言級別實現面向物件工程
建議多用多型

1.4:依賴倒轉原則

依賴於抽像(介面),不要依賴具體的實現(類),也就是針對介面程式設計。

在這裡插入圖片描述

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

/*class benchi
{
public:
	void run()
	{
		cout << "賓士啟動" << endl;
	}
};

class bm
{
public:
	void run()
	{
		cout << "寶馬啟動" << endl;
	}
};
class zhangsan
{
public:
	void drivebenchi(benchi* b)
	{
		b->run;
	}
	void drivebm(bm* b)
	{
		b->run;
	}
};*/	
//改進:如果人多了,車型別多,那麼就會很亂,複雜,所以可以抽喜抽喜car,司機類
//抽像層
class Driver
{
public:
	virtual void drive(Car* car) = 0;
};
class Car
{
public:
	virtual void run() = 0;
};
//實現層
class zhangsan:public Driver
{
public:
	virtual void drive(Car* car)
	{
		cout << "zhangsan" << endl;
		car->run;
	}
};

class lisi:public Driver
{
public:
	virtual void drive(Car* car)
	{
		cout << "lisi" << endl;
		car->run;
	}

};
class benchi :public Car
{
public:
	virtual void run()
	{
		cout << "benchi" << endl;
	}

};
class bm :public Car
{
public:
	virtual void run()
	{
		cout << "bm" << endl;
	}

};
int main()
{
	/*//張三開賓士
	benchi *b = new benchi;
	zhangsan *z = new zhangsan;
	z->drivebenchi(b);

	//張三開寶馬
	bm *m= new bm;
	z->drivebm(m);
	 */

	//優點:運用的類少
	//邏輯層與實現層通過抽象層隔離叫做解耦合
	//zhangsan開賓士
	Car	*b = new benchi;
	Driver *d = new zhangsan;
	d->drive(b);
	delete(b);
	delete(d);

	//lisi開寶馬
	Car	*b = new bm;
	Driver *d = new lisi;
	delete(b);
	delete(d);

	d->drive(b);
	system("pause");
	return 0;
}

例:電腦組裝案例

在這裡插入圖片描述

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <Windows.h>
using namespace std;

//抽象層
class CPU
{
public:
	virtual void caculate() = 0;
};
class Card
{
public:
	virtual void dispaly() = 0;
};
class Memory
{
public:
	virtual void storage() = 0;
};

//架構層 (包含所有抽像類)
class computer
{
public:
	computer(CPU* cpu, Card* card, Memory* mermory)
	{
		this->cpu = cpu;
		this->card = card;
		this->memory = memory;

	}
	void work()
	{
		cpu->caculate();
		card->dispaly();
		memory->storage();
	}
private:
	CPU* cpu;
	Card* card;
	Memory* memory;
};

//實現層 (那個廠商生產)
class interCPU:public CPU
{
public:
	void caculate()
	{
		cout <<"caculaet"<<endl;

	}
};
class interCard:public Card
{
public:
	void display()
	{
		cout << "display" << endl;

	}
};
class interMemory:public Memory
{
public:
	void storage()
	{
		cout << "storage" << endl;

	}
};
//高業務層
int main()
{
	CPU* cpu = new interCPU;
	Card* card = new interCard;
	Memory* mem = new interMemory;
	computer* com = new computer(cpu,card,mem);

	com->work();
	delete(cpu);
	delete(card);
	delete(mem);
	delete(com);
	system("pause");
	return 0;
}
1.5:介面隔離原則(單一功能)

不應該強迫使用者的程式依賴他們不需要的介面方法,一個介面應該只是提供一種對外功能,不應該吧所有操作都封裝到一個介面去,

1.6:合成複用原則

如果使用繼承,會導致父類的任何交換都可能影響到子類的行為,如果使用物件組合,就降低了這種依賴關係,對於繼承與組合優先使用組合。

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <Windows.h> 
using namespace std;

class Cat
{
public:
	void sleep()
	{
		cout << "睡覺"<< endl;
	}
};

//建立一個新的貓,且增加一個功能,即能睡覺又能吃東西
//如果Cat有很多父類,cat的父類與AddCat高耦合,複雜度高
//通過繼承完成
class AddCat:public Cat
{
public:
	void eat()
	{
		cout << "吃飯"<< endl;
		sleep();
	}
};

//使用組合方式新增吃東西
//使用組合降低Add2Cat與Cat耦合,跟Cat父類沒有任何關係,
//只跟Cat與slepp有關係
class Add2Cat
{
public:
	Add2Cat(Cat* cat)
	{
		this->cat = cat;
	}
	void eat(Cat* cat)
	{
		cout <<"吃飯" << endl;
		cat->sleep();
	}
private:
	Cat* cat;
};
int main()
{
	Cat c;
	c.sleep();

	AddCat ac;
	ac.eat();

	Add2Cat ac(&c);
	ac.eat();

	system("pause");
	return 0;
}
1.7:迪米特法則(知道最少原則)

一個物件應儘可能少的瞭解其他物件,從而降低各個物件之間的耦合度,提高系統的可維護性,例如一個程式中,各個模組之間相互呼叫,通常會提供一個統一的介面,來實現,這樣其他模組不需要了解另一個模組的內部實現原理,當一個模組的內部的實現發生改變時,不會影響其他模組的使用(黑盒原理)
【類比種類就是這個原理】
在這裡插入圖片描述