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); }
可以看的出,对应相同的功能,面向对象的设计方式比分解的设计方式改动要少的多。
代码的复用性也好的多。