从重构入手,了解设计模式。
一、实现软件
完成一个图形软件,画出Line和我Rect
方法一:分解
#include <iostream>
#include <vector>
using namespace std;
//画图
class Point
{
public:
int m_x;
int m_y;
};
class Line
{
public:
Line(){std::cout << "Line" << std::endl;}
void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect
{
public:
Rect() {std::cout << "Rect" << std::endl;}
void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Paint
{
public:
vector<Line> m_vecLine;
vector<Rect> m_vecRect;
//添加
void paintData(int type)
{
if (type == 1)
{
Line line;
m_vecLine.push_back(line);
}
else if(type == 2)
{
Rect rect;
m_vecRect.push_back(rect);
}
}
//显示(分解处理)
void paintShow()
{
for(vector<Line>::iterator ite = m_vecLine.begin(); ite != m_vecLine.end(); ite++)
{
ite->draw(1);
}
for(vector<Rect>::iterator ite = m_vecRect.begin(); ite != m_vecRect.end(); ite++)
{
ite->draw(1);
}
}
};
int main()
{
Paint p;
//添加图形
p.paintData(1);
p.paintData(2);
//显示图形
p.paintShow();
}
//打印以下内容
Line
Rect
draw line
draw Rect
方法二:抽象
#include <iostream>
#include <vector>
using namespace std;
//画图
class Point
{
public:
int m_x;
int m_y;
};
class sharpe //不同处
{
public:
virtual ~sharpe(){};
virtual void draw(int i){};
};
class Line : public sharpe
{
public:
Line(){std::cout << "Line" << std::endl;}
void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect : public sharpe
{
public:
Rect() {std::cout << "Rect" << std::endl;}
void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Paint
{
public:
vector<sharpe *> m_vecPic;//不同处
//添加
void paintData(int type)
{
if (type == 1)
{
m_vecPic.push_back(new Line);
}
else if(type == 2)
{
m_vecPic.push_back(new Rect);
}
}
//显示(抽象统一处理)
void paintShow()
{
//不同处
for(vector<sharpe*>::iterator ite = m_vecPic.begin(); ite != m_vecPic.end(); ite++)
{
(*ite)->draw(1);
}
}
};
int main()
{
Paint p;
//添加图形
p.paintData(1);
p.paintData(2);
//显示图形
p.paintShow();
}
//打印以下内容
Line
Rect
draw line
draw Rect
二、实现一需求更改
现在把上面的需求再增加一个,多了一个circle打印圆形的功能
方法一:分解(更改后,需要修改5个地方)
#include <iostream>
#include <vector>
using namespace std;
//画图
class Point
{
public:
int m_x;
int m_y;
};
class Line
{
public:
Line(){std::cout << "Line" << std::endl;}
void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect
{
public:
Rect() {std::cout << "Rect" << std::endl;}
void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Circle //1
{
public:
Circle() {std::cout << "Circle" << std::endl;}
void draw (int i){std::cout << "draw Circle" << std::endl;}
};
class Paint
{
public:
vector<Line> m_vecLine;
vector<Rect> m_vecRect;
vector<Circle> m_vecCircle; //2
//添加
void paintData(int type)
{
if (type == 1)
{
Line line;
m_vecLine.push_back(line);
}
else if(type == 2)
{
Rect rect;
m_vecRect.push_back(rect);
}
else if(type == 3) //3
{
Circle circle;
m_vecCircle.push_back(circle);
}
}
//显示
void paintShow()
{
for(vector<Line>::iterator ite = m_vecLine.begin(); ite != m_vecLine.end(); ite++)
{
ite->draw(1);
}
for(vector<Rect>::iterator ite = m_vecRect.begin(); ite != m_vecRect.end(); ite++)
{
ite->draw(1);
}
for(vector<Circle>::iterator ite = m_vecCircle.begin(); ite != m_vecCircle.end(); ite++) //4
{
ite->draw(1);
}
}
};
int main()
{
Paint p;
//添加图形
p.paintData(1);
p.paintData(2);
p.paintData(3);
//显示图形
p.paintShow();
}
方法二:抽象(更改后,只更改了两个地方)
#include <iostream>
#include <vector>
using namespace std;
//画图
class Point
{
public:
int m_x;
int m_y;
};
class sharpe
{
public:
virtual ~sharpe(){};
virtual void draw(int i){};
};
class Line : public sharpe
{
public:
Line(){std::cout << "Line" << std::endl;}
void draw (int i){std::cout << "draw line" << std::endl;}
};
class Rect : public sharpe
{
public:
Rect() {std::cout << "Rect" << std::endl;}
void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Circle : public sharpe //1
{
public:
Circle() {std::cout << "Circle" << std::endl;}
void draw (int i){std::cout << "draw Circle" << std::endl;}
};
class Paint
{
public:
vector<sharpe *> m_vecPic;
//添加
void paintData(int type)
{
if (type == 1)
{
m_vecPic.push_back(new Line);
}
else if(type == 2)
{
m_vecPic.push_back(new Rect);
}
else if(type == 3)
{
m_vecPic.push_back(new Circle); //2
}
}
//显示
void paintShow()
{
for(vector<sharpe*>::iterator ite = m_vecPic.begin(); ite != m_vecPic.end(); ite++)
{
(*ite)->draw(1);
}
}
};
int main()
{
Paint p;
//添加图形
p.paintData(1);
p.paintData(2);
p.paintData(3);
//显示图形
p.paintShow();
}
//打印以下内容
Line
Rect
Circle
draw line
draw Rect
draw Circle
结论:
抽象比分解解决问题修改起来更方便,可复用性强
C++小知识
class A;
class B;
class C;继承自B
vector<A> t;
vector<B*> t; //使用指针可以使用多态
#include <iostream>
#include <vector>
using namespace std;
enum COLOR
{
RED=1, YELLO, BLACK, WHITE
};
//画图
class Point
{
public:
int m_x;
int m_y;
};
class sharpe
{
public:
virtual ~sharpe(){};
virtual void draw(int i){}; //3,没有变化的draw1、draw2\ 5继承的人都有用到draw
};
class Color
{
public:
int curColor(){}
};
class Pen
{
public:
Color color;
void setColor(int i) {}
};
class Line : public sharpe
{
public:
Pen m_pen; //6
//Color Ccolor;//8 color在pen里面使用,这里不能使用
void setPen(Pen &pen){ m_pen = pen; }
Line(){std::cout << "Line" << std::endl;}
void draw (int i){drawTest();std::cout << "draw line" << std::endl;}
private:
void drawTest(){} //5
};
class Rect : public sharpe
{
public:
Rect() {std::cout << "Rect" << std::endl;}
void draw (int i){std::cout << "draw Rect" << std::endl;}
};
class Circle : public sharpe
{
public:
Circle() {std::cout << "Circle" << std::endl;}
void draw (int i){std::cout << "draw Circle" << std::endl;}
};
class Paint
{
public:
vector<sharpe *> m_vecPic; //1 4-1
//添加
void paintData(int type)
{
if (type == 1)
{
m_vecPic.push_back(new Line);//4-2
}
else if(type == 2)
{
m_vecPic.push_back(new Rect);
}
else if(type == 3)
{
m_vecPic.push_back(new Circle); //2
}
}
//显示
void paintShow()
{
for(vector<sharpe*>::iterator ite = m_vecPic.begin(); ite != m_vecPic.end(); ite++)
{
(*ite)->draw(1); //2(不是每个Line\Rect都要重新固定,重新写)
}
}
};
int main()
{
Paint p;
//添加图形
p.paintData(1);
p.paintData(2);
p.paintData(3);
//显示图形
p.paintShow();
}
//打印以下内容
Line
Rect
Circle
draw line
draw Rect
draw Circle
7大设计模式原则
1.依赖倒置原则DIP(面对接口编程,不要对实现编程)
高层模块(稳定)不依赖底层模块(变化),二者都要依赖抽象(稳定)
抽象(稳定)不依赖实现细节(变化),实现细节应该依赖抽象(稳定)
如:vector m_vecPic; 针对接口,而不是真实类型
2.开放封闭原则(OCP)
对扩展开放,对更改封闭
如上例需要添加画圆圈,秩序添加Class Circle即可,其他不用更改
3.单一职责原则(SRP)
一个类只有一个引起它变化的原因,比如:
比如:sharp类只有一个draw类是变化的,需要与众不同的。
4.Liskov替换原则(LSP)
子类必须能替换父类(父类的功能,子类不能有父类同名的非虚函数)
继承表达,类型抽象(Line和Rect两个对外统一为sharpe替换)
5.接口隔离原则(ISP)
接口要小(不是接口的函数都用private)
继承的接口类那些虚函数都要有用到,不然就把他拆分掉,使用多继承
6.优先使用对象组合而不是类继承(继承应该是生物和动物的包含关系,而不是简单的父亲和儿子的继承关系)
继承子类和父类耦合度高
对象组合要求对象接口的合作,耦合度低
7.封装变化点
封装变化点,一侧稳定,一侧变化。稳定如Paint类,是变化的,而Sharpe是稳定的,Line和Rect是变化的。
8.迪米特原则(最少知道原则)
一个类里面不管属性还是行为,用到的其他类尽量少。
设计模式需要遵循
需求变化的点和稳定的点
提高复用
重构而不是直接使用设计模式
设计模式从重构开始-重构关键方法
a 静态-》动态(A::test() 调用改为 a->test();)
b 早绑定-》晚绑定 (void printTest(A &a){ a.test(); } A应该只是一个接口类,并且test是一个虚函数)https://blog.csdn.net/a133900029/article/details/80185428
c 继承-》组合(类A继承类B 改为 类A包含类B元素)
d 编译时依赖-》运行时依赖()
e 紧耦合-》松耦合(分接口出来)