从面向对象谈起
1)
底层思维:向下,如何把握及其底层,从微观理解对象构造
(语言构造、编译转换、内存模型、运行时机制)
抽象思维: 向上,如何将我们的周围世界抽象为程序代码
(面向对象、组件封装、设计模式、架构模式)
2)
深入理解面向对象
向下: 深入理解三大面向对象机制(封装、继承、多态)
向上:深刻把握面向对象机制所带来的抽象意义,掌握如何使用这些机制来表达现实世界。
掌握什么是”好的面向对象设计“。 (不是使用了封装、继承、多态就是面向对象)
3)
软件设计复杂的根本原因: 变化!
4)如何解决复杂性? (分解与抽象)
分解:分而治之,将大问题分解为多个小问题,复杂问题分解为简单问题
抽象:更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。
由于不能掌握全部的复杂对象,我们选择忽略它的非本质细节,而去处理泛化和理想化的对象模型
5)代码示例:画图简单工具代码描述 (伪代码,关注业务逻辑,体会分解与抽象的不同)
两种实现方法描述
第一种实现:(分解)
Shape1 中, 各自建立Point,Line,Rec类
Mainform1中,建立存储不同类型图形的数据结构(vector<Point>, vector<Line>...);
鼠标点击时根据类型判断存储在不同结构中;
Onpaint方法依次实现不同图形画法。
第二种实现:(抽象)
Shape2中,建立Shape基类和draw虚函数;
Point Line Rec等继承Shape类,并override draw函数,自己画自己。
Mainform2中,建立存储基类指针的数据结构(vector<Shape*>),实现对所有形状存储;
鼠标点击时根据类型判断以不同方式存储在 vector<Shape*>中, 如 = new Rec() 或 = new Line()
Onpaint方法,多态调用,各负其责。
孰优孰劣? 评判标准?
功能均可实现,但考虑实现好坏的标准应该要考虑变化!
变化: 增加circle类和其画法
对于第一种实现: 36-40行 增加circle类; 53行 增加vector<Circle>; 89-93行 增加对Circle判断和存储; 120 -125行增加画circle的
对于第二种实现:54-62行 增加circle类继承shape; 107-111行增加对Circle判断和存储(采用工厂模式也可消除该变化)
可以看出第二种是实现代码变更部分更少(尤其不必修改内部代码,只是额外添加),代码复用性更强,抵御变化能力更强。
6) 回到软件设计的目标
软件设计的金科玉律: 复用!
shape1 & Mainform1 :
1 //Shape1.h 2 // 3 4 class Point{ 5 public: 6 int x; 7 int y; 8 }; 9 10 class Line{ 11 public: 12 Point start; 13 Point end; 14 15 Line(const Point& start, const Point& end){ 16 this->start = start; 17 this->end = end; 18 } 19 20 }; 21 22 class Rect{ 23 public: 24 Point leftUp; 25 int width; 26 int height; 27 28 Rect(const Point& leftUp, int width, int height){ 29 this->leftUp = leftUp; 30 this->width = width; 31 this->height = height; 32 } 33 34 }; 35 36 //增加 37 class Circle{ 38 39 40 }; 41 42 //Mainform1.cpp 43 // 44 45 class MainForm : public Form { 46 private: 47 Point p1; 48 Point p2; 49 50 vector<Line> lineVector; 51 vector<Rect> rectVector; 52 //改变 53 vector<Circle> circleVector; 54 55 public: 56 MainForm(){ 57 //... 58 } 59 protected: 60 61 virtual void OnMouseDown(const MouseEventArgs& e); 62 virtual void OnMouseUp(const MouseEventArgs& e); 63 virtual void OnPaint(const PaintEventArgs& e); 64 }; 65 66 67 void MainForm::OnMouseDown(const MouseEventArgs& e){ 68 p1.x = e.X; 69 p1.y = e.Y; 70 71 //... 72 Form::OnMouseDown(e); 73 } 74 75 void MainForm::OnMouseUp(const MouseEventArgs& e){ 76 p2.x = e.X; 77 p2.y = e.Y; 78 79 if (rdoLine.Checked){ 80 Line line(p1, p2); 81 lineVector.push_back(line); 82 } 83 else if (rdoRect.Checked){ 84 int width = abs(p2.x - p1.x); 85 int height = abs(p2.y - p1.y); 86 Rect rect(p1, width, height); 87 rectVector.push_back(rect); 88 } 89 //改变 90 else if (...){ 91 //... 92 circleVector.push_back(circle); 93 } 94 95 //... 96 this->Refresh(); 97 98 Form::OnMouseUp(e); 99 } 100 101 void MainForm::OnPaint(const PaintEventArgs& e){ 102 103 //针对直线 104 for (int i = 0; i < lineVector.size(); i++){ 105 e.Graphics.DrawLine(Pens.Red, 106 lineVector[i].start.x, 107 lineVector[i].start.y, 108 lineVector[i].end.x, 109 lineVector[i].end.y); 110 } 111 112 //针对矩形 113 for (int i = 0; i < rectVector.size(); i++){ 114 e.Graphics.DrawRectangle(Pens.Red, 115 rectVector[i].leftUp, 116 rectVector[i].width, 117 rectVector[i].height); 118 } 119 120 //改变 121 //针对圆形 122 for (int i = 0; i < circleVector.size(); i++){ 123 e.Graphics.DrawCircle(Pens.Red, 124 circleVector[i]); 125 } 126 127 //... 128 Form::OnPaint(e); 129 }
shape2 & Mainform2 :
1 //Shape2 2 // 3 class Shape{ 4 public: 5 virtual void Draw(const Graphics& g)=0; 6 virtual ~Shape() { } 7 }; 8 9 10 class Point{ 11 public: 12 int x; 13 int y; 14 }; 15 16 class Line: public Shape{ 17 public: 18 Point start; 19 Point end; 20 21 Line(const Point& start, const Point& end){ 22 this->start = start; 23 this->end = end; 24 } 25 26 //实现自己的Draw,负责画自己 27 virtual void Draw(const Graphics& g){ 28 g.DrawLine(Pens.Red, 29 start.x, start.y,end.x, end.y); 30 } 31 32 }; 33 34 class Rect: public Shape{ 35 public: 36 Point leftUp; 37 int width; 38 int height; 39 40 Rect(const Point& leftUp, int width, int height){ 41 this->leftUp = leftUp; 42 this->width = width; 43 this->height = height; 44 } 45 46 //实现自己的Draw,负责画自己 47 virtual void Draw(const Graphics& g){ 48 g.DrawRectangle(Pens.Red, 49 leftUp,width,height); 50 } 51 52 }; 53 54 //增加 55 class Circle : public Shape{ 56 public: 57 //实现自己的Draw,负责画自己 58 virtual void Draw(const Graphics& g){ 59 g.DrawCircle(Pens.Red, 60 ...); 61 } 62 63 }; 64 65 //Mainform2 66 // 67 class MainForm : public Form { 68 private: 69 Point p1; 70 Point p2; 71 72 //针对所有形状 73 vector<Shape*> shapeVector; 74 75 public: 76 MainForm(){ 77 //... 78 } 79 protected: 80 81 virtual void OnMouseDown(const MouseEventArgs& e); 82 virtual void OnMouseUp(const MouseEventArgs& e); 83 virtual void OnPaint(const PaintEventArgs& e); 84 }; 85 86 87 void MainForm::OnMouseDown(const MouseEventArgs& e){ 88 p1.x = e.X; 89 p1.y = e.Y; 90 91 //... 92 Form::OnMouseDown(e); 93 } 94 95 void MainForm::OnMouseUp(const MouseEventArgs& e){ 96 p2.x = e.X; 97 p2.y = e.Y; 98 99 if (rdoLine.Checked){ 100 shapeVector.push_back(new Line(p1,p2)); 101 } 102 else if (rdoRect.Checked){ 103 int width = abs(p2.x - p1.x); 104 int height = abs(p2.y - p1.y); 105 shapeVector.push_back(new Rect(p1, width, height)); 106 } 107 //改变 (使用工厂模式这里的变化也可消除) 108 else if (...){ 109 //... 110 shapeVector.push_back(circle); 111 } 112 113 //... 114 this->Refresh(); 115 116 Form::OnMouseUp(e); 117 } 118 119 void MainForm::OnPaint(const PaintEventArgs& e){ 120 121 //针对所有形状 122 for (int i = 0; i < shapeVector.size(); i++){ 123 124 shapeVector[i]->Draw(e.Graphics); //多态调用,各负其责 125 } 126 127 //... 128 Form::OnPaint(e); 129 }