設計模式(一)——何爲設計模式,從重構開始設計模式

從重構入手,瞭解設計模式。

一、實現軟件

完成一個圖形軟件,畫出Line和我Rect

方法一:分解

#include <iostream>
#include <vector>
using namespace std;
//畫圖
class Point
{
public:
	int m_x;
	int m_y;
};

class Line
{
public:
	Line(){std::cout << "Line" << std::endl;}
	void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect
{
public:
	Rect() {std::cout << "Rect" << std::endl;}
	void draw (int i){std::cout << "draw Rect" << std::endl;}
};

class Paint
{
public:
	vector<Line> m_vecLine;
	vector<Rect> m_vecRect;

	//添加
	void paintData(int type)
	{
		if (type == 1)
		{
			Line line;
			m_vecLine.push_back(line);
		}
		else if(type == 2)
		{
			Rect rect;
			m_vecRect.push_back(rect);
		}
	}
	//顯示(分解處理)
	void paintShow() 
	{
		for(vector<Line>::iterator ite = m_vecLine.begin(); ite != m_vecLine.end(); ite++)
		{
			ite->draw(1);
		}
		for(vector<Rect>::iterator ite = m_vecRect.begin(); ite != m_vecRect.end(); ite++)
		{
			ite->draw(1);
		}
	}

	
};


int main()
{
	Paint p;
	//添加圖形
	p.paintData(1);
	p.paintData(2);
	//顯示圖形
	p.paintShow();
}
//打印以下內容
Line
Rect
draw line
draw Rect

方法二:抽象

#include <iostream>
#include <vector>
using namespace std;
//畫圖
class Point
{
public:
	int m_x;
	int m_y;
};

class sharpe //不同處
{
public:
	virtual ~sharpe(){};
	virtual void draw(int i){};
};
class Line : public sharpe
{
public:
	Line(){std::cout << "Line" << std::endl;}
	void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect : public sharpe
{
public:
	Rect() {std::cout << "Rect" << std::endl;}
	void draw (int i){std::cout << "draw Rect" << std::endl;}
};

class Paint
{
public:
	vector<sharpe *> m_vecPic;//不同處

	//添加
	void paintData(int type)
	{
		if (type == 1)
		{
			m_vecPic.push_back(new Line);
		}
		else if(type == 2)
		{
			m_vecPic.push_back(new Rect);
		}
	}
	//顯示(抽象統一處理)
	void paintShow() 
	{
          //不同處
		for(vector<sharpe*>::iterator ite = m_vecPic.begin(); ite != m_vecPic.end(); ite++)
		{
			(*ite)->draw(1);
		}
	}
};


int main()
{
	Paint p;
	//添加圖形
	p.paintData(1);
	p.paintData(2);
	//顯示圖形
	p.paintShow();
}


//打印以下內容
Line
Rect
draw line
draw Rect

二、實現一需求更改

現在把上面的需求再增加一個,多了一個circle打印圓形的功能

方法一:分解(更改後,需要修改5個地方)

#include <iostream>
#include <vector>
using namespace std;
//畫圖
class Point
{
public:
	int m_x;
	int m_y;
};

class Line
{
public:
	Line(){std::cout << "Line" << std::endl;}
	void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect
{
public:
	Rect() {std::cout << "Rect" << std::endl;}
	void draw (int i){std::cout << "draw Rect" << std::endl;}
};

class Circle //1
{
public:
	Circle() {std::cout << "Circle" << std::endl;}
	void draw (int i){std::cout << "draw Circle" << std::endl;}
};

class Paint
{
public:
	vector<Line> m_vecLine;
	vector<Rect> m_vecRect;
	vector<Circle> m_vecCircle; //2

	//添加
	void paintData(int type)
	{
		if (type == 1)
		{
			Line line;
			m_vecLine.push_back(line);
		}
		else if(type == 2)
		{
			Rect rect;
			m_vecRect.push_back(rect);
		}
		else if(type == 3) //3
		{
			Circle circle;
			m_vecCircle.push_back(circle);
		}
	}
	//顯示
	void paintShow() 
	{
		for(vector<Line>::iterator ite = m_vecLine.begin(); ite != m_vecLine.end(); ite++)
		{
			ite->draw(1);
		}
		for(vector<Rect>::iterator ite = m_vecRect.begin(); ite != m_vecRect.end(); ite++)
		{
			ite->draw(1);
		}
		for(vector<Circle>::iterator ite = m_vecCircle.begin(); ite != m_vecCircle.end(); ite++) //4
		{
			ite->draw(1);
		}
	}

	
};


int main()
{
	Paint p;
	//添加圖形
	p.paintData(1);
	p.paintData(2);
	p.paintData(3);
	//顯示圖形
	p.paintShow();
}

方法二:抽象(更改後,只更改了兩個地方)

#include <iostream>
#include <vector>
using namespace std;
//畫圖
class Point
{
public:
	int m_x;
	int m_y;
};

class sharpe
{
public:
	virtual ~sharpe(){};
	virtual void draw(int i){};
};
class Line : public sharpe
{
public:
	Line(){std::cout << "Line" << std::endl;}
	void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect : public sharpe
{
public:
	Rect() {std::cout << "Rect" << std::endl;}
	void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Circle : public sharpe  //1
{
public:
	Circle() {std::cout << "Circle" << std::endl;}
	void draw (int i){std::cout << "draw Circle" << std::endl;}
};

class Paint
{
public:
	vector<sharpe *> m_vecPic;

	//添加
	void paintData(int type)
	{
		if (type == 1)
		{
			m_vecPic.push_back(new Line);
		}
		else if(type == 2)
		{
			m_vecPic.push_back(new Rect);
		}
		else if(type == 3)
		{
			m_vecPic.push_back(new Circle);  //2
		}
	}
	//顯示
	void paintShow() 
	{
		for(vector<sharpe*>::iterator ite = m_vecPic.begin(); ite != m_vecPic.end(); ite++)
		{
			(*ite)->draw(1);
		}
	}
};


int main()
{
	Paint p;
	//添加圖形
	p.paintData(1);
	p.paintData(2);
	p.paintData(3);
	//顯示圖形
	p.paintShow();
}

//打印以下內容
Line
Rect
Circle
draw line
draw Rect
draw Circle

結論:

抽象比分解解決問題修改起來更方便,可複用性強

C++小知識

class A;
class B;
class C;繼承自B
vector<A> t; 
vector<B*> t; //使用指針可以使用多態
#include <iostream>
#include <vector>
using namespace std;
enum COLOR
{
      RED=1, YELLO, BLACK, WHITE
};
//畫圖
class Point
{
public:
	int m_x;
	int m_y;
};

class sharpe
{
public:
	virtual ~sharpe(){};
	virtual void draw(int i){}; //3,沒有變化的draw1、draw2\ 5繼承的人都有用到draw
};

class Color
{
public:
    int curColor(){}
};

class Pen
{
public:
    Color color;
    void setColor(int i) {}      
};

class Line : public sharpe
{
public:
    Pen m_pen; //6 
    //Color Ccolor;//8 color在pen裏面使用,這裏不能使用
    void setPen(Pen &pen){ m_pen = pen; }
	Line(){std::cout << "Line" << std::endl;}
	void draw (int i){drawTest();std::cout << "draw line" << std::endl;}
private:
    void drawTest(){}  //5
};
class Rect : public sharpe
{
public:
	Rect() {std::cout << "Rect" << std::endl;}
	void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Circle : public sharpe  
{
public:
	Circle() {std::cout << "Circle" << std::endl;}
	void draw (int i){std::cout << "draw Circle" << std::endl;}
};

class Paint
{
public:
	vector<sharpe *> m_vecPic;  //1   4-1

	//添加
	void paintData(int type)
	{
		if (type == 1)
		{
			m_vecPic.push_back(new Line);//4-2
		}
		else if(type == 2)
		{
			m_vecPic.push_back(new Rect);
		}
		else if(type == 3)
		{
			m_vecPic.push_back(new Circle);  //2
		}
	}
	//顯示
	void paintShow() 
	{
		for(vector<sharpe*>::iterator ite = m_vecPic.begin(); ite != m_vecPic.end(); ite++)
		{
			(*ite)->draw(1);  //2(不是每個Line\Rect都要重新固定,重新寫)
		}
	}
};


int main()
{
	Paint p;
	//添加圖形
	p.paintData(1);
	p.paintData(2);
	p.paintData(3);
	//顯示圖形
	p.paintShow();
}

//打印以下內容
Line
Rect
Circle
draw line
draw Rect
draw Circle

設計模式七大原則(C++描述)

7大設計模式原則

1.依賴倒置原則DIP(面對接口編程,不要對實現編程)
高層模塊(穩定)不依賴底層模塊(變化),二者都要依賴抽象(穩定)
抽象(穩定)不依賴實現細節(變化),實現細節應該依賴抽象(穩定)
如:vector m_vecPic; 針對接口,而不是真實類型
在這裏插入圖片描述
2.開放封閉原則(OCP)
對擴展開放,對更改封閉
如上例需要添加畫圓圈,秩序添加Class Circle即可,其他不用更改
3.單一職責原則(SRP)
一個類只有一個引起它變化的原因,比如:
比如:sharp類只有一個draw類是變化的,需要與衆不同的。
4.Liskov替換原則(LSP)
子類必須能替換父類(父類的功能,子類不能有父類同名的非虛函數)
繼承表達,類型抽象(Line和Rect兩個對外統一爲sharpe替換)
5.接口隔離原則(ISP)
接口要小(不是接口的函數都用private)
繼承的接口類那些虛函數都要有用到,不然就把他拆分掉,使用多繼承
6.優先使用對象組合而不是類繼承(繼承應該是生物和動物的包含關係,而不是簡單的父親和兒子的繼承關係)
繼承子類和父類耦合度高
對象組合要求對象接口的合作,耦合度低
7.封裝變化點
封裝變化點,一側穩定,一側變化。穩定如Paint類,是變化的,而Sharpe是穩定的,Line和Rect是變化的。
8.迪米特原則(最少知道原則)
一個類裏面不管屬性還是行爲,用到的其他類儘量少。

設計模式需要遵循

需求變化的點和穩定的點
提高複用
重構而不是直接使用設計模式

設計模式從重構開始-重構關鍵方法

a 靜態-》動態(A::test() 調用改爲 a->test();)
b 早綁定-》晚綁定 (void printTest(A &a){ a.test(); } A應該只是一個接口類,並且test是一個虛函數)https://blog.csdn.net/a133900029/article/details/80185428
c 繼承-》組合(類A繼承類B 改爲 類A包含類B元素)
d 編譯時依賴-》運行時依賴()
e 緊耦合-》鬆耦合(分接口出來)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章