设计模式第一讲--设计模式简介

1. 课程目标

(1)理解松耦合设计思想

(2)掌握面向对象设计原则

(3)掌握重构技法改善设计

(4)掌握GOF核心设计模式

 

2. 《设计模式:可复用面向对象软件的基础》

可复用是设计模式的目标,面向对象是方法。通常说的设计模式默认为面向对象的设计模式,但这并不意味着设计模式就等于面向对象的设计模式。

 

3. 底层思维:向下,如何把握机器底层从围观理解对象构造

语言构造、编译转换、内存模型、运行时机制。

抽象思维:向上,如何将我们的周围世界抽象为程序代码

面向对象、组件封装、设计模式、架构模式。

 

深入理解面向对象:

向下:深入理解三大面向对象机制

封装:隐藏内部实现

继承:复用现有代码

多态:修改对象行为

 

向上:深刻把握面向对象机制所带来的抽象意义,理解如何使用这些机制来表达现实世界,掌握什么是“好的面向对象设计”。

 

4. 如何解决复杂性?

(1)分解 分而治之,将大问题分解成多个小问题,将复杂问题分解为多个简单问题。

(2)抽象 更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。由于不能掌握全部的复杂对象,我们选择忽视它的非本质细节,而去处理泛化和理想化了的对象模型。

 

5.假设在一个界面上可以绘制线条和矩形

(1)用分解的思路实现,伪代码如下:

shape.h文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#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 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);
    }
 
    //...
    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文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#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文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#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 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 (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文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#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 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));
    }
 
    //...
    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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#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 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 (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);
}  

 

可以看的出,对应相同的功能,面向对象的设计方式比分解的设计方式改动要少的多。

代码的复用性也好的多。

 

posted on   xcxfury001  阅读(28)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示