变化是设计中最大的挑战,是复用的天敌。而使用抽象的面向对象设计最大优势就是抵御变化。
设计原则比设计模式更重要。有了设计原则呢,你可以发明自己的模式;你也可以去理解其他一些新的设计模式,或其他的设计模式。
一个错误的观点:把模式当成算法来学习。
- 两段代码非常像,但可能表达的是完全不同的设计模式
- 有的时候,两段代码千差万别,但可能表达的是同一个设计模式
- 评判设计模式的规则是设计原则,而不是代码本身,实现本身。是按照设计原则来归类的。
将设计原则提升为设计经验
设计经验有三类
| 类型 | 说明 |
|---|---|
| 设计习语 Design Idioms |
描述与特定编程语言相关的低层模式、技巧、惯用法。比如C++中的《Effective C++》等 |
| 设计模式 Design Patterns |
描述“类与相互通信的对象之间的组织关系”,包括它们的角色、职责、协作方式等方面。主要解决的是变化中的复用性问题 |
| 架构模式 Architectural Patterns |
描述系统中基本结构组织关系密切的高层模式,包括子系统划分,职责,以及如何组织它们之间关系的规则 |
示例
示例中包含两种思维模型,在接下来会以这两个例子来说明设计原则。
以一个画图工具为例,说明两种思维模型
- 一开始的需求:需要实现画线、画矩形两个方法
- 需求变更:需要在画线画矩阵的基础上,添加画圆
第一种思维模型:分解(结构化编程)
分而治之,针对圆形怎么做、针对矩形怎么做,针对圆怎么做
- MainForm.cpp
```cpp
class MainForm : public Form {
private:
Point p1; //鼠标点的第一个点
Point p2; //鼠标点的第二个点
//当下需求只有画线、画矩形
vector
lineVector; vector rectVector; //需求变更后,新增画圆 vector 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);}//刷新则调用onPaintthis->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);
}
2. shape.h```cppclass 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{};
第二种思维模型:抽象(面向对象)
MainFrom.cpp ```cpp class MainForm : public Form { private: Point p1; Point p2;
//不需要一个类型一个数组,只需要一个父类指针就可对所有形状的描述 vector
shapeVector; //说明:这里不能是vector ,如果LineString赋值给Shape,会变成Shape结构空间 //这样就不能有多态性,Shape只能表示它自己,而不能表示子类
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);
}
2. shape.h```cppclass 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 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,...);}};
