设计模式简介

 

什么是设计模式,结构化设计和抽象化设计的区别

什么是设计模式,结构化设计和抽象化设计的区别

什么是设计模式

“每一个模式描述了一个在我们周围不断重复发生的问题, 以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”

思维

  • 底层思维
    • 构建机器模型
    • 元素的组合运转机制
  • 抽象思维
    • 将世界抽象为程序代码
    • • 面向对象 • 组件封装 • 设计模式 • 架构模式
  • 深入理解面向对象
    • 向下
      • 封装,隐藏内部实现
      • 继承,复用现有代码
      • 多态,改写对象行为
    • 向上
      • 把握面向对象机制所带来的抽象意义
      • 如何使用这些机制来表达现实世界
  • 抽象思维的引入
    • 软件的复杂性
    • 根本:需求的变化
  • 如何解决复杂性
    • 分解(分而治之)
    • 把不同的可能(变化)从笼统中分出来
    • 针对每一个变化写出应对的函数
    • 大问题分解为多个小问题
    • 复杂问题分解为多个简单问题
    • 抽象(统而治之)
      • 解决更高层次的问题
      • 把不同的可能(变化)归类到一个抽象体系中,统一的来处理

结构化 VS 面向对象

  • 有一个画图的应用,鼠标按下记录点p1,鼠标抬起记录p2;
  • 如果事先选择画线,则把p1,p2连起来
  • 如果事先选择画矩形,则把p1,p2框起来

    结构化

  1. 创建好点、线、矩形的类
     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;
         }
     };
    
  2. 主框架mainForm
     class MainForm : public Form {
     private:
         Point p1;
         Point p2;
    
         vector<Line> lineVector;
         vector<Rect> rectVector;
         //改变
         vector<Circle> circleVector;
    
     public:
         MainForm(){
             //...
         }
     protected:
    
         virtual void OnMouseDown(const MouseEventArgs& e);
         virtual void OnMouseUp(const MouseEventArgs& e);
         virtual void OnPaint(const PaintEventArgs& e);
     };
    
  3. 鼠标按下记录点p1
     void MainForm::OnMouseDown(const MouseEventArgs& e){
         p1.x = e.X;
         p1.y = e.Y;
    
         //...
         Form::OnMouseDown(e);
     }
    
  4. 鼠标抬起记录p2
     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);
     }
    
  5. 画画
     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);
     }
    

面向对象

  1. 增加shape的父类
     class Shape{
     public:
         virtual void Draw(const Graphics& g)=0;
         virtual ~Shape() { }
     };
    
  2. 线和矩形都继承shap
     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);
         }
     };
    
  3. 主框架mainForm
    • 把各个具体的线、矩形形状换成了Shape这个父类
    • 所以一个vector<Shape*>就可以应对所有的类型
     class MainForm : public Form {
     private:
         Point p1;
         Point p2;
    
         //针对所有形状,对象指针
         vector<Shape*> shapeVector;
    
     public:
         MainForm(){
             //...
         }
     protected:
    
         virtual void OnMouseDown(const MouseEventArgs& e);
         virtual void OnMouseUp(const MouseEventArgs& e);
         virtual void OnPaint(const PaintEventArgs& e);
     };
    
  4. 鼠标按下记录点p1
     void MainForm::OnMouseDown(const MouseEventArgs& e){
         p1.x = e.X;
         p1.y = e.Y;
    
         //...
         Form::OnMouseDown(e);
     }
    
  5. 鼠标抬起记录p2
     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);
     }
    
  6. 显示图形
     void MainForm::OnPaint(const PaintEventArgs& e){
    
         //针对所有形状
         for (int i = 0; i < shapeVector.size(); i++){
    
             shapeVector[i]->Draw(e.Graphics); //多态调用,各负其责
         }
    
         //...
         Form::OnPaint(e);
     }
    

区别

  • 当要加入圆形需求时
    • 结构化设计需要:
      • 增加圆形的类Circle{点、半径、new()构造器}
      • 在主框架mainForm中增加 vector<Circle> circleVector
      • 在鼠标抬起时,增加如果先前选择圆形的情况,把一个新的圆形对象放入circle_vec
      • 在显示图形的函数中,加上对circle_vec对象列表的遍历和绘制
    • 抽象化设计
      • 增加圆形的类Circle{点、半径、new()构造器},
        • 继承Shape类
        • Circle类实现自己的draw绘制方法
      • (不动)mainForm中是vector<Shape*>,Circle也是Shape类型
      • 在鼠标抬起时,增加如果先前选择圆形的情况,把一个新的圆形对象放入shape_vec
      • (不动)在显示图形的函数中,任然是遍历shape_vec,调用每个shape.draw()方法

软件设计的目标

设计模式的目标就是软件的复用性