C++设计模式课件1_介绍.pdf.pdf

什么时候设计模式?

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

GOF设计模式

Design Patterns: Elements of Reusable Object-Oriented Software
中译名: 设计模式 可复用面向对象软件的基础

从面向对象谈起

底层思维->程序员<-抽象思维

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

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

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

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

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

  • 封装,隐藏内部实现

  • 继承,复用现有代码
  • 多态,改写对象行为

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

软件设计固有的复杂性-变化

建筑商从来不会去想给一栋已建好的100层高的 楼房底下再新修一个小地下室——这样做花费极大而且注定要失败。然而令人惊奇的是,软件系统的用户在要求作出类似改变时却不会仔细考虑,而且他们认为这只是需要简单编程的事。
——Object-Oriented Analysis and Design with Applications

软件设计复杂的根本原因-变化

  • 客户需求的变化
  • 技术平台的变化
  • 开发团队的变化
  • 市场环境的变化

如何解决复杂性?

分解

  • 人们面对复杂性有一个常见的做法:即分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单问题。

抽象

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

代码示例 1. 结构化 VS. 面向对象

伪代码

方式1: 分解

  1. // shape.h
  2. class Point{
  3. public:
  4. int x;
  5. int y;
  6. };
  7. class Line{
  8. public:
  9. Point start;
  10. Point end;
  11. Line(const Point& start, const Point& end){
  12. this->start = start;
  13. this->end = end;
  14. }
  15. };
  16. class Rect{
  17. public:
  18. Point leftUp;
  19. int width;
  20. int height;
  21. Rect(const Point& leftUp, int width, int height){
  22. this->leftUp = leftUp;
  23. this->width = width;
  24. this->height = height;
  25. }
  26. };
  27. //增加
  28. class Circle{
  29. };
  1. // MainForm.cpp
  2. class MainForm : public Form {
  3. private:
  4. Point p1;
  5. Point p2;
  6. vector<Line> lineVector;
  7. vector<Rect> rectVector;
  8. //改变
  9. vector<Circle> circleVector;
  10. public:
  11. MainForm(){
  12. //...
  13. }
  14. protected:
  15. virtual void OnMouseDown(const MouseEventArgs& e);
  16. virtual void OnMouseUp(const MouseEventArgs& e);
  17. virtual void OnPaint(const PaintEventArgs& e);
  18. };
  19. void MainForm::OnMouseDown(const MouseEventArgs& e){
  20. p1.x = e.X;
  21. p1.y = e.Y;
  22. //...
  23. Form::OnMouseDown(e);
  24. }
  25. void MainForm::OnMouseUp(const MouseEventArgs& e){
  26. p2.x = e.X;
  27. p2.y = e.Y;
  28. if (rdoLine.Checked){
  29. Line line(p1, p2);
  30. lineVector.push_back(line);
  31. }
  32. else if (rdoRect.Checked){
  33. int width = abs(p2.x - p1.x);
  34. int height = abs(p2.y - p1.y);
  35. Rect rect(p1, width, height);
  36. rectVector.push_back(rect);
  37. }
  38. //改变
  39. else if (...){
  40. //...
  41. circleVector.push_back(circle);
  42. }
  43. //...
  44. this->Refresh();
  45. Form::OnMouseUp(e);
  46. }
  47. void MainForm::OnPaint(const PaintEventArgs& e){
  48. //针对直线
  49. for (int i = 0; i < lineVector.size(); i++){
  50. e.Graphics.DrawLine(Pens.Red,
  51. lineVector[i].start.x,
  52. lineVector[i].start.y,
  53. lineVector[i].end.x,
  54. lineVector[i].end.y);
  55. }
  56. //针对矩形
  57. for (int i = 0; i < rectVector.size(); i++){
  58. e.Graphics.DrawRectangle(Pens.Red,
  59. rectVector[i].leftUp,
  60. rectVector[i].width,
  61. rectVector[i].height);
  62. }
  63. //改变
  64. //针对圆形
  65. for (int i = 0; i < circleVector.size(); i++){
  66. e.Graphics.DrawCircle(Pens.Red,
  67. circleVector[i]);
  68. }
  69. //...
  70. Form::OnPaint(e);
  71. }

方式2: 抽象

  1. // shape.h
  2. class Shape{
  3. public:
  4. virtual void Draw(const Graphics& g)=0;
  5. virtual ~Shape() { }
  6. };
  7. class Point{
  8. public:
  9. int x;
  10. int y;
  11. };
  12. class Line: public Shape{
  13. public:
  14. Point start;
  15. Point end;
  16. Line(const Point& start, const Point& end){
  17. this->start = start;
  18. this->end = end;
  19. }
  20. //实现自己的Draw,负责画自己
  21. virtual void Draw(const Graphics& g){
  22. g.DrawLine(Pens.Red,
  23. start.x, start.y,end.x, end.y);
  24. }
  25. };
  26. class Rect: public Shape{
  27. public:
  28. Point leftUp;
  29. int width;
  30. int height;
  31. Rect(const Point& leftUp, int width, int height){
  32. this->leftUp = leftUp;
  33. this->width = width;
  34. this->height = height;
  35. }
  36. //实现自己的Draw,负责画自己
  37. virtual void Draw(const Graphics& g){
  38. g.DrawRectangle(Pens.Red,
  39. leftUp,width,height);
  40. }
  41. };
  42. //增加
  43. class Circle : public Shape{
  44. public:
  45. //实现自己的Draw,负责画自己
  46. virtual void Draw(const Graphics& g){
  47. g.DrawCircle(Pens.Red,
  48. ...);
  49. }
  50. };

推荐public继承

  1. // MainForm.cpp
  2. class MainForm : public Form {
  3. private:
  4. Point p1;
  5. Point p2;
  6. //针对所有形状
  7. vector<Shape*> shapeVector;
  8. public:
  9. MainForm(){
  10. //...
  11. }
  12. protected:
  13. virtual void OnMouseDown(const MouseEventArgs& e);
  14. virtual void OnMouseUp(const MouseEventArgs& e);
  15. virtual void OnPaint(const PaintEventArgs& e);
  16. };
  17. void MainForm::OnMouseDown(const MouseEventArgs& e){
  18. p1.x = e.X;
  19. p1.y = e.Y;
  20. //...
  21. Form::OnMouseDown(e);
  22. }
  23. void MainForm::OnMouseUp(const MouseEventArgs& e){
  24. p2.x = e.X;
  25. p2.y = e.Y;
  26. if (rdoLine.Checked){
  27. shapeVector.push_back(new Line(p1,p2));
  28. }
  29. else if (rdoRect.Checked){
  30. int width = abs(p2.x - p1.x);
  31. int height = abs(p2.y - p1.y);
  32. shapeVector.push_back(new Rect(p1, width, height));
  33. }
  34. //改变
  35. else if (...){
  36. //...
  37. shapeVector.push_back(circle);
  38. }
  39. //...
  40. this->Refresh();
  41. Form::OnMouseUp(e);
  42. }
  43. void MainForm::OnPaint(const PaintEventArgs& e){
  44. //针对所有形状
  45. for (int i = 0; i < shapeVector.size(); i++){
  46. shapeVector[i]->Draw(e.Graphics); //多态调用,各负其责
  47. }
  48. //...
  49. Form::OnPaint(e);
  50. }

vector<Shape*> shapeVector

  • 为了支持多态性,如果不用指针,会导致对象切割

shapeVector.push_back(new Line(p1,p2))

  • 不能放栈对象,而要放堆对象,注意释放

shapeVector[i]->Draw(e.Graphics)

  • 多态调用,各负其责
  • 根据内部存储的实际类型

方式1和方式2哪种更好?

需求变化

  • 需要画一个圆形

方式2代码变更更少,重用性更高

软件设计的目标-复用性