设计模式第一讲--设计模式简介

1. 课程目标

(1)理解松耦合设计思想

(2)掌握面向对象设计原则

(3)掌握重构技法改善设计

(4)掌握GOF核心设计模式

 

2. 《设计模式:可复用面向对象软件的基础》

可复用是设计模式的目标,面向对象是方法。通常说的设计模式默认为面向对象的设计模式,但这并不意味着设计模式就等于面向对象的设计模式。

 

3. 底层思维:向下,如何把握机器底层从围观理解对象构造

语言构造、编译转换、内存模型、运行时机制。

抽象思维:向上,如何将我们的周围世界抽象为程序代码

面向对象、组件封装、设计模式、架构模式。

 

深入理解面向对象:

向下:深入理解三大面向对象机制

封装:隐藏内部实现

继承:复用现有代码

多态:修改对象行为

 

向上:深刻把握面向对象机制所带来的抽象意义,理解如何使用这些机制来表达现实世界,掌握什么是“好的面向对象设计”。

 

4. 如何解决复杂性?

(1)分解 分而治之,将大问题分解成多个小问题,将复杂问题分解为多个简单问题。

(2)抽象 更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。由于不能掌握全部的复杂对象,我们选择忽视它的非本质细节,而去处理泛化和理想化了的对象模型。

 

5.假设在一个界面上可以绘制线条和矩形

(1)用分解的思路实现,伪代码如下:

shape.h文件内容

#pragma once

class Point
{
public:
	int x;
	int y;
};

class Line
{
public:
	Point start;
	Point end;

	Line(const Point& start, const Point& end)
	{
		this->start = start;
		this->end = end;
	}
};

class Rect
{
public:
	Point leftUp;
	int width;
	int height;

	Rect(const Point& leftUP, int width, int height)
	{
		this->leftUp = leftUP;
		this->height = height;
		this->width = width;
	}
};

  每一个形状对应各自的类。

MainForm.cpp中的内容

#include "Shape.h"

#include<vector>

using namespace std;

class MainForm :public Form
{
private:
	Point p1;    //表示鼠标按下和抬起的点
	Point p2;

	vector<Line> lineVector;
	vector<Rect> rectVector;

public:
	MainForm()
	{
		//...
	}

protected:
	virtual void onm ouseDown(const MouseEventArgs& e);   //鼠标按下
	virtual void onm ouseUp(const MouseEventArgs& e);     //鼠标抬起
	virtual void OnPaint(const PaintEventArgs& e);       //界面刷新
};

void MainForm::OnMouseDown(const MouseEventArgs& e)
{
	p1.x = e.X;
	p1.y = e.Y;

	//...
	Form::OnMouseDown(e);
}

void MainForm::OnMouseUp(const MouseEventArgs& e)
{
	p2.x = e.X;
	p2.y = e.Y;

	if (rdoLine.Checked)
	{
		Line Line(p1, p2);
		LineVector.push_back(line);
	}
	else if (rdoRect.Checked)
	{
		int width = abs(p2.x - p1.x);
		int height = abs(p2.y - p1.y);
		Rect rect(p1, width, height);
		rectVector.push_back(rect);
	}

	//...
	this->Refresh();   //系统会调用OnPaint

	Form::OnMouseUp(e);
}

void MainForm::OnPaint(const PaintEventArgs& e)
{
	//针对直线
	for (int i = 0; i < lineVector.size(); i++)
	{
		e.Graphics.DrawLine(Pens.red,
			lineVector[i].start.x,
			lineVector[i].start.y,
			lineVector[i].end.x,
			lineVector[i].end.y);
	}

	//针对矩形
	for (int i = 0; i < rectVector.size(); i++)
	{
		e.Graphics.DrawRectangle(Pens.red,
			rectVector[i].leftUp,
			rectVector[i].width,
			rectVector[i].height);
	}

	//...
	Form::OnPaint(e);
}

  现在有一个需求,要求可以再界面上绘制圆形。

为了实现这个目标,书写的代码如下:

shape.h文件

#pragma once

class Point
{
public:
	int x;
	int y;
};

class Line
{
public:
	Point start;
	Point end;

	Line(const Point& start, const Point& end)
	{
		this->start = start;
		this->end = end;
	}
};

class Rect
{
public:
	Point leftUp;
	int width;
	int height;

	Rect(const Point& leftUP, int width, int height)
	{
		this->leftUp = leftUP;
		this->height = height;
		this->width = width;
	}
};

//新加代码
class Circle
{
public:
	Point Center;
	int Radius;

	Circle(const Point& center, int radius)
	{
		this->Center = center;
		this->Radius = radius;
	}
};

  MainForm.cpp文件内容

#include "Shape.h"

#include<vector>

using namespace std;

class MainForm :public Form
{
private:
	Point p1;    //表示鼠标按下和抬起的点
	Point p2;

	vector<Line> lineVector;
	vector<Rect> rectVector;
	vector<Circle> circleVector;

public:
	MainForm()
	{
		//...
	}

protected:
	virtual void onm ouseDown(const MouseEventArgs& e);   //鼠标按下
	virtual void onm ouseUp(const MouseEventArgs& e);     //鼠标抬起
	virtual void OnPaint(const PaintEventArgs& e);       //界面刷新
};

void MainForm::OnMouseDown(const MouseEventArgs& e)
{
	p1.x = e.X;
	p1.y = e.Y;

	//...
	Form::OnMouseDown(e);
}

void MainForm::OnMouseUp(const MouseEventArgs& e)
{
	p2.x = e.X;
	p2.y = e.Y;

	if (rdoLine.Checked)
	{
		Line Line(p1, p2);
		LineVector.push_back(line);
	}
	else if (rdoRect.Checked)
	{
		int width = abs(p2.x - p1.x);
		int height = abs(p2.y - p1.y);
		Rect rect(p1, width, height);
		rectVector.push_back(rect);
	}
	else if (rdoCircle.Checked)
	{
		Point center;
		center.x = (p1.x + p2.x) / 2;
		center.y = (p1.y + p2.y) / 2;

		int radius = sqrt(pow(abs(p1.x - p2.x), 2) + pow(abs(p1.y - p2.y), 2)) / 2;

		Circle circle(center,radius);
		circleVector.push_back(circle);
	}

	//...
	this->Refresh();   //系统会调用OnPaint

	Form::OnMouseUp(e);
}

void MainForm::OnPaint(const PaintEventArgs& e)
{
	//针对直线
	for (int i = 0; i < lineVector.size(); i++)
	{
		e.Graphics.DrawLine(Pens.red,
			lineVector[i].start.x,
			lineVector[i].start.y,
			lineVector[i].end.x,
			lineVector[i].end.y);
	}

	//针对矩形
	for (int i = 0; i < rectVector.size(); i++)
	{
		e.Graphics.DrawRectangle(Pens.red,
			rectVector[i].leftUp,
			rectVector[i].width,
			rectVector[i].height);
	}

	//针对圆形
	for (int i = 0; i < circleVector.size(); i++)
	{
		e.Graphics.DrawCircle(Pens.red,
			rectVector[i].Center,
			rectVector[i].Radius);
	}

	//...
	Form::OnPaint(e);
}

(2)抽象的思路实现界面上可以绘制直线和矩形的功能

Shape1.h文件内容

#pragma once

class Shape
{
public:
	virtual void Draw(const Graphics& g) = 0;
	virtual ~Shape() {}
};

class Point
{
public:
	int x;
	int y;
};

class Line : public Shape
{
public:
	Point start;
	Point end;

	Line(const Point& start, const Point& end)
	{
		this->start = start;
		this->end = end;
	}

	//实现自己的Draw,负责画自己
	virtual void Draw(const Graphic& g)
	{
		g.DrawLine(Pens.red, start.x, start.y, end.x, end.y);
	}
};

class Rect :public Shape
{
public:
	Point leftUp;
	int width;
	int height;

	Rect(const Point& leftUp, int width, int height)
	{
		this->leftUp = leftUp;
		this->width = width;
		this->height = height;
	}

	//实现自己的Draw,负责画自己
	virtual void Draw(const Graphics& g)
	{
		g.DrawRectangle(Pens.red, leftUp, width, height);
	}
};

  创建名为Shape的基类,线条类和矩形类都继承Shape基类,其再各自的类中实现Draw方法。

MainForm1.cpp

#include "Shape1.h"

#include<vector>

using namespace std;

class MainForm : public Form
{
private:
	Point p1;
	Point p2;

	//针对所有形状
	vector<Shape*> shapeVector;   //析构的时候需要释放这个地方的内存

public:
	MainForm()
	{
		//...
	}

protected:
	virtual void onm ouseDown(const MouseEventArgs& e);   //鼠标按下
	virtual void onm ouseUp(const MouseEventArgs& e);     //鼠标抬起
	virtual void OnPaint(const PaintEventArgs& e);       //界面刷新
};

void MainForm::OnMouseDown(const MouseEventArgs& e)
{
	p1.x = e.X;
	p1.y = e.Y;

	//...
	Form::OnMouseDown(e);
}

void MainForm::OnMouseUp(const MouseEventArgs& e)
{
	p2.x = e.X;
	p2.y = e.Y;

	if (rdoLine.Checked)
	{
		shapeVector.push_back(new Line(p1, p2));
	}
	else if (rdoRect.Checked)
	{
		int width = abs(p2.x - p1.x);
		int height = abs(p2.y - p1.y);
		shapeVector.push_back(new Rect(p1, width, height));
	}

	//...
	this->Refresh();   //系统会调用OnPaint

	Form::OnMouseUp(e);
}

void MainForm::OnPaint(const PaintEventArgs& e)
{
	//针对所有形状
	for (int i = 0; i < shapeVector.size(); i++)
	{
		//多态调用,各负其责
		shapeVector[i]->Draw(e.Graphics);
	}

	//...
	Form::OnPaint(e);
}

  那这个时候,只需要再MainForm类中创建存储Shape*的vector数组就好,不必针对每一中类型创建vector了。

那现在我们有相同的需求,都是在界面上可以绘制圆形。对应修改的代码如下:

Shape1.h

#pragma once

class Shape
{
public:
	virtual void Draw(const Graphics& g) = 0;
	virtual ~Shape() {}
};

class Point
{
public:
	int x;
	int y;
};

class Line : public Shape
{
public:
	Point start;
	Point end;

	Line(const Point& start, const Point& end)
	{
		this->start = start;
		this->end = end;
	}

	//实现自己的Draw,负责画自己
	virtual void Draw(const Graphic& g)
	{
		g.DrawLine(Pens.red, start.x, start.y, end.x, end.y);
	}
};

class Rect :public Shape
{
public:
	Point leftUp;
	int width;
	int height;

	Rect(const Point& leftUp, int width, int height)
	{
		this->leftUp = leftUp;
		this->width = width;
		this->height = height;
	}

	//实现自己的Draw,负责画自己
	virtual void Draw(const Graphics& g)
	{
		g.DrawRectangle(Pens.red, leftUp, width, height);
	}
};

class Circle :public Shape
{
public:
	Point Center;
	int Radius;

	Circle(const Point& center, int radius)
	{
		this->Center = center;
		this->Radius = radius;
	}

	// 实现自己的Draw,负责画自己
	virtual void Draw(const Graphics & g)
	{
		g.DrawCircle(Pens.red, Center, Radius);
	}
};

  MainForm.cpp

#include "Shape1.h"

#include<vector>

using namespace std;

class MainForm : public Form
{
private:
	Point p1;
	Point p2;

	//针对所有形状
	vector<Shape*> shapeVector;   //析构的时候需要释放这个地方的内存

public:
	MainForm()
	{
		//...
	}

protected:
	virtual void onm ouseDown(const MouseEventArgs& e);   //鼠标按下
	virtual void onm ouseUp(const MouseEventArgs& e);     //鼠标抬起
	virtual void OnPaint(const PaintEventArgs& e);       //界面刷新
};

void MainForm::OnMouseDown(const MouseEventArgs& e)
{
	p1.x = e.X;
	p1.y = e.Y;

	//...
	Form::OnMouseDown(e);
}

void MainForm::OnMouseUp(const MouseEventArgs& e)
{
	p2.x = e.X;
	p2.y = e.Y;

	if (rdoLine.Checked)
	{
		shapeVector.push_back(new Line(p1, p2));
	}
	else if (rdoRect.Checked)
	{
		int width = abs(p2.x - p1.x);
		int height = abs(p2.y - p1.y);
		shapeVector.push_back(new Rect(p1, width, height));
	}
	else if (rdoCircle.Checked)
	{
		Point center;
		center.x = (p1.x + p2.x) / 2;
		center.y = (p1.y + p2.y) / 2;

		int radius = sqrt(pow(abs(p1.x - p2.x), 2) + pow(abs(p1.y - p2.y), 2)) / 2;

		shapeVector.push_back(new Circle(center, radius));
	}

	//...
	this->Refresh();   //系统会调用OnPaint

	Form::OnMouseUp(e);
}

void MainForm::OnPaint(const PaintEventArgs& e)
{
	//针对所有形状
	for (int i = 0; i < shapeVector.size(); i++)
	{
		//多态调用,各负其责
		shapeVector[i]->Draw(e.Graphics);
	}

	//...
	Form::OnPaint(e);
}  

 

可以看的出,对应相同的功能,面向对象的设计方式比分解的设计方式改动要少的多。

代码的复用性也好的多。

 

上一篇:202006 csp认证


下一篇:剑指 day 3【JZ52 两个链表的第一个公共结点】增加链表长度以使双指针起效