做网站界面需要注意什么问题,摄影设计思路,网站换dns,手机怎么做电子书下载网站文章目录 本栏简介1. 什么是设计模式2. GOF 设计模式3. 从面向对象谈起4. 深入理解面向对象5. 软件设计固有的复杂性5.1 软件设计复杂性的根本原因5.2 如何解决复杂性 ? 6. 结构化 VS. 面向对象6.1 同一需求的分解写法6.1.1 Shape1.h6.1.2 MainForm1.cpp 6.2 同一需求的抽象的… 文章目录 本栏简介1. 什么是设计模式2. GOF 设计模式3. 从面向对象谈起4. 深入理解面向对象5. 软件设计固有的复杂性5.1 软件设计复杂性的根本原因5.2 如何解决复杂性 ? 6. 结构化 VS. 面向对象6.1 同一需求的分解写法6.1.1 Shape1.h6.1.2 MainForm1.cpp 6.2 同一需求的抽象的写法6.2.1 shape2.h6.2.2 MainForm2.cpp 6.3 两种方法的分析6.3.1 Shape*与Shape的使用6.3.2 第一种设计和第二种设计对比 7. 软件设计的目标 本栏简介
本栏目将会介绍设计模式的相关内容目标如下
理解松耦合设计思想掌握面向对象设计原则掌握重构技法改善设计掌握GOF 核心设计模式
1. 什么是设计模式
软件领域的设计模式是参考一个建筑学家提出的进行定义的。
“每一个模式描述了一个在我们周围不断重复发生的问题以及该问题的解决方案的核心。这样你就能一次又一次地使用该方案而不必做重复劳动” -Christopher Alexander
也就是不用再重新开发轮子
2. GOF 设计模式
本栏目推荐的教材如下因为是四个人94年写的这本书GOF也有四人团的说法。 历史性著作《设计模式:可复用面向对象软件的基础》一书中描述了23种经典面向对象设计模式创立了模式在软件设计中的地位。 可复用是设计模式的目标面向对象是具体的方法 由于《设计模式》一书确定了设计模式的地位通常所说的设计模式隐含地表示“面向对象设计模式”。但这并不意味“设计模式就等于“面向对象设计模式。 3. 从面向对象谈起
面向对象的设计模式很重要的一点就是从面向对象谈起。 面向对象背后藏着两种思维模型
底层思维 人和计算机之间的沟通建立机器模型: 向下如何把握机器底层从微观理解对象构造 语言构造编译转换内存模型运行时机制 异常处理、垃圾收集器进行内存管理
底层思维可以帮助程序员建立机器模型很多C的高手也是从这一步开始的但是光有底层思维还是不够伴随着工作经验的增长抽象思维会显得很重要。
抽象思维: 向上如何将我们的周围世界抽象为程序代码 面向对象组件封装设计模式架构模式 抽象思维可以帮助我们很好的关系代码的复杂度。
4. 深入理解面向对象
光有抽象思维而没有底层思维很有可能代码是写不好的所以这两种思维需要并重而本栏目更倾向于抽象思维。 向下深入理解三大面向对象机制 封装隐藏内部实现继承复用现有代码多态改写对象行为 向上: 深刻把握面向对象机制所带来的抽象意义理解如何使用这些机制来表达现实世界掌握什么是“好的面向对象设计。
5. 软件设计固有的复杂性
首先需要谈抽象思维的背景即软件设计固有的复杂性。 建筑商从来不会去想给一栋已建好的100层高的楼房底下再新修一个小地下室-这样做花费极大而且注定要失败。然而令人惊奇的是软件系统的用户在要求作出类似改变时却不会仔细考虑而且他们认为这只是需要简单编程的事。-Object-Oriented Analysis and Design with Applications
5.1 软件设计复杂性的根本原因
软件设计复杂性的根本原因即变化。
客户需求的变化技术平台的变化开发团队的变化市场环境的变化 …
5.2 如何解决复杂性 ?
分解复用性差 人们面对复杂性有一个常见的做法即分而治之将大问题分解为多个小问题将复杂问题分解为多个简单问题。 抽象统一处理不用分而治之 更高层次来讲人们处理复杂性有一个通用的技术即抽象。由于不能掌握全部的复杂对象我们选择忽视它的非本质细节而去处理泛化和理想化了的对象模型。
所有的设计模式都是围绕着抽象关键词进行变化。
下面通过代码来理解分解和抽象。
6. 结构化 VS. 面向对象
此处均为伪码不要紧的删除只保留能表达关键设计的代码
6.1 同一需求的分解写法
6.1.1 Shape1.h
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-width width;this-height height;}};//增加
class Circle{};
上面的代码没有太遵循C的编码规范。
例如
public:int x;int y;字段作为实现是细节是需要定义为private的但是那么写的话就会写的很长。 还有不同的Class需要放在独立的文件中为了方便代码展示就将不同的类放在了一个文件中。
6.1.2 MainForm1.cpp
假设有一个窗口MainForm以下程序是在界面上划线画矩形等。 class MainForm : public Form {
private:Point p1; //描述鼠标移动留下的点的轨迹Point p2;vectorLine lineVector;vectorRect rectVector;//改变vectorCircle circleVector;public:MainForm(){//...}
protected:virtual void OnMouseDown(const MouseEventArgs e);virtual void OnMouseUp(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 (...){//...circleVector.push_back(circle);}//...this-Refresh();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,circleVector[i]);}//...Form::OnPaint(e);
}以上即为分解的设计方法
6.2 同一需求的抽象的写法
6.2.1 shape2.h
//
class Shape{
public:virtual void Draw(const Graphics g)0;virtual ~Shape() { } //虚析构函数作用通过多态释放的时候子类的析构函数才会被调用到
};class Point{
public:int x;int y;
};
//所有的继承推荐使用public很少使用其他类型
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 Graphics 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://实现自己的Draw负责画自己virtual void Draw(const Graphics g){g.DrawCircle(Pens.Red,...);}};6.2.2 MainForm2.cpp
class MainForm : public Form {
private:Point p1;Point p2;//针对所有形状没必要像上面设计数据结构vectorShape* shapeVector; public:MainForm(){//...}
protected:virtual void OnMouseDown(const MouseEventArgs e);virtual void OnMouseUp(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 (...){//...shapeVector.push_back(circle);}//...this-Refresh();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);
}6.3 两种方法的分析
6.3.1 Shape*与Shape的使用
MainForm2.cpp中需要多态此处虽然是Shape*类型但是可能真正塞得是Line、Rect、Circle类。 如果不使用Shape*而使用Shape会导致对象切割假如传的是Line就会将其切割为小对象后期会再进行梳理此处只要理解需要使用shape指针来表达多态性而不能使用shape对象。 //针对所有形状没必要像上面设计数据结构vectorShape* shapeVector; MainForm1.cpp中存储的是对象不需要多态 vectorLine lineVector;vectorRect rectVector;6.3.2 第一种设计和第二种设计对比
为了证实哪种设计更好我们需要假设在客户需求发生变化时对程序员来说哪种方式复用性更强。
假设存在一种变化比如客户需求变化客户需要增加实现圆circle上面的代码已经是增加了circle的可以对两种方法进行对比可以发现在第一种设计方法的改变内容要大于第二种方法也就是第二种设计方式重用性得到了提升。
7. 软件设计的目标
什么是好的软件设计 ?软件设计的金科玉律 复用性
大家必须深刻理解 抽象 这种设计模式和目标后期介绍利用抽象的设计思想针对不同领域的不同问题提出不同的模式进行解决。