模式:在某些场景下,针对某类问题的某种通用解决方案
简单工厂模式
一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例
// 抽象产品类
class Product {
public:
virtual void show() = 0;
};
// 产品类A
class ProductA : public Product{
public:
void show(){ cout<<"Product A"<<'\n'; }
};
// 产品类B
class ProductB : public Product{
public:
void show(){ cout<<"Product B"<<'\n'; }
};
// 工厂类
class simpleFactory{
public:
Product* CreateProduct(string str){
if(str == "A") m_product = new ProductA();
else if(str == "B") m_product = new ProductB();
return m_product;
}
private:
Product* m_product;
};
工厂方法模式
简单工厂模式要加功能,需要添加更多的if,不符合设计模式中的开放封闭原则,为了进一步解耦,在简单工厂的基础上发展出了工厂方法模式,即连工厂都抽象出来,实现了进一步代码解耦。
// 抽象产品类
class Product {
public:
virtual void show() = 0;
};
// 产品类A
class ProductA : public Product{
public:
void show(){ cout<<"Product A"<<'\n'; }
};
// 产品类B
class ProductB : public Product{
public:
void show(){ cout<<"Product B"<<'\n'; }
};
// 抽象工厂类
class Factory{
public:
virtual Product* CreateProduct() = 0;
};
// 工厂类A
class FactoryA : public Factory{
public:
Product* CreateProduct(){
return new ProductA();
}
};
// 工厂类B
class FactoryB : public Factory{
public:
Product* CreateProduct(){
return new ProductB();
}
};
抽象工厂模式
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个
// 抽象产品类A
class AbstractProductA {
public:
virtual void show() = 0;
};
// 抽象产品类B
class AbstractProductB {
public:
virtual void show() = 0;
};
// 产品类A
class ProductA : public AbstractProductA{
public:
void show(){ cout<<"Product A"<<'\n'; }
};
// 产品类B
class ProductB : public AbstractProductB{
public:
void show(){ cout<<"Product B"<<'\n'; }
};
// 抽象工厂类
class Factory{
public:
virtual AbstractProductA* CreateProductA() = 0;
virtual AbstractProductB* CreateProductB() = 0;
};
// 工厂类
class CreateFactory : public Factory{
public:
AbstractProductA* CreateProductA(){ return new ProductA(); }
AbstractProductB* CreateProductB(){ return new ProductB(); }
};
策略模式
策略模式是一种行为型模式,定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
class Operation{
public:
Operation():_numberA(0),_numberB(0){}
void setNumberA(double value){
_numberA = value;
}
double getNumberA(){
return _numberA;
}
void setNumberB(double value){
_numberB = value;
}
double getNumberB(){
return _numberB;
}
virtual double getResult() = 0;
protected:
double _numberA;
double _numberB;
};
class OperationAdd : public Operation{
public:
virtual double getResult(){
return _numberA + _numberB;
}
};
class OperationSub : public Operation{
public:
virtual double getResult(){
return _numberA - _numberB;
}
};
class OperationMul : public Operation{
public:
virtual double getResult(){
return _numberA * _numberB;
}
};
class OperationDiv : public Operation{
public:
virtual double getResult(){
if(-0.00000001 < _numberB && _numberB < 0.00000001)
throw exception("除数不能为0");
return _numberA / _numberB;
}
};
class OperationFactoryContext{
public:
OperationFactoryContext():oper(nullptr){}
~OperationFactoryContext(){
delete oper;
}
void createOperate(double valueA, char operate, double valueB){
switch(operate){
case '+':
oper = new OperationAdd();
break;
case '-':
oper = new OperationSub();
break;
case '*':
oper = new OperationMul();
break;
case '/':
oper = new OperationDiv();
break;
default:
throw exception("操作符错误\n");
}
oper->setNumberA(valueA);
oper->setNumberB(valueB);
}
double getResult(){
return oper->getResult();
}
private:
Operation *oper;
};
简单工厂模式和策略模式的区别
工厂模式主要是返回的接口实现类的实例化对象,最后返回的结果是接口实现类中的方法,而策略模式是在实例化策略模式的时候已经创建好了,我们可以在策略模式中随意的拼接重写方法,而工厂模式是不管方法的拼接这些的,他只关注最后的结果,不注重过程,而策略模式注重的是过程。
单一职责原则
单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。
一个类职责太多的缺点:
- 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;
- 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。
开放封闭原则
开放-封闭原则,是说软件实体(类、模块、函数等)应该可以扩展,但是不可修改。即扩展是开放的,更改是封闭的。
面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。可维护、可扩展、可复用、灵活性好。
依赖倒转原则
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。
依赖倒转原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。
依赖倒转可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之就是面向过程化的设计了。
里氏代换原则
子类型必须能够替换掉它们的父类型。一个软件实体如果使用的是一个父类的话,那么一定是用于其子类,而且察觉不出父类对象和子类对象的区别,即把父类都替换成它的子类,程序的行为没有变化。
装饰模式
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
using namespace std;
//抽象构件
class Component{
public:
virtual void Operation() = 0;
};
//具体构件
class ConcreteComponent:public Component{
public:
ConcreteComponent(){
cout<<"创建具体构件角色"<<"\n";
}
void Operation(){
cout<<"具体对象的操作"<<'\n';
}
};
//抽象装饰
class Decorator:public Component{
public:
Decorator(Component* component):m_component(component){}
void Operation(){
m_component->Operation();
}
private:
Component* m_component;
};
//具体装饰
class ConcreteDecorator:public Decorator{
public:
ConcreteDecorator(Component* component):Decorator(component){}
void Operation(){
Decorator::Operation();
addedFunction();
}
private:
void addedFunction(){
cout<<"为具体构件角色增加额外的功能"<<'\n';
}
};
int main(){
Component* c = new ConcreteComponent();
Component* d = new ConcreteDecorator(c);
d->Operation();
}
代理模式
为其他对象提供一种代理以控制这个对象的访问。
using namespace std;
// 共用接口
class Subject{
public:
virtual void Request() = 0;
};
// 真实实体
class RealSubject:public Subject{
public:
void Request() {
cout<<"真实的请求"<<'\n';
}
};
// 代理
class Proxy:public Subject{
RealSubject* realSubject;
public:
Proxy(){
realSubject = new RealSubject();
}
void Request() {
realSubject->Request();
}
~Proxy(){
if(realSubject){
delete realSubject;
}
}
};
int main(){
Proxy* proxy = new Proxy();
proxy->Request();
delete proxy;
return 0;
}
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。其实就是从一个对象再创建另一个可定制的对象,而且不需知道任何创建的细节。通过复制现有的实例来创建新的实例。
using namespace std;
// 接口
class Prototype{
public:
Prototype(){}
virtual ~Prototype(){}
virtual Prototype* Clone() = 0;
};
class ConcretePrototype : public Prototype{
public:
ConcretePrototype():m_counter(0){}
// 拷贝构造函数
ConcretePrototype(const ConcretePrototype& rhs){
m_counter = rhs.m_counter;
}
// 复制自身
ConcretePrototype* Clone(){
return new ConcretePrototype(*this);
}
private:
int m_counter;
};
int main(){
ConcretePrototype* conProA = new ConcretePrototype();
ConcretePrototype* conProB = conProA->Clone();
delete conProA;
delete conProB;
return 0;
}
模板方法模式
定义一个算法结构,将一些步骤延迟到子类实现。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。
using namespace std;
class AbstractClass{
public:
virtual void PrimitiveOperation1() = 0;
virtual void PrimitiveOperation2() = 0;
void TemplateMethod(){
PrimitiveOperation1();
PrimitiveOperation2();
}
};
class ConcreteClassA : public AbstractClass{
public:
void PrimitiveOperation1(){
cout<<"类A方法1实现"<<'\n';
}
void PrimitiveOperation2(){
cout<<"类A方法2实现"<<'\n';
}
};
class ConcreteClassB : public AbstractClass{
public:
void PrimitiveOperation1(){
cout<<"类B方法1实现"<<'\n';
}
void PrimitiveOperation2(){
cout<<"类B方法2实现"<<'\n';
}
};
int main(){
AbstractClass* A;
AbstractClass* B;
A = new ConcreteClassA();
A->TemplateMethod();
B = new ConcreteClassB();
B->TemplateMethod();
delete A;
delete B;
return 0;
}
迪杰特法则
如果两个类不必彼此通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。其根本思想,是强调类之间的松耦合。
外观模式
为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。对外提供一个统一的方法,来访问子系统中的一组接口。
using namespace std;
class SubSystemOne{
public:
void MethodOne(){
cout<<"子系统方法一"<<'\n';
}
};
class SubSystemTwo{
public:
void MethodTwo(){
cout<<"子系统方法二"<<'\n';
}
};
class SubSystemThree{
public:
void MethodThree(){
cout<<"子系统方法三"<<'\n';
}
};
class SubSystemFour{
public:
void MethodFour(){
cout<<"子系统方法四"<<'\n';
}
};
class Facade{
public:
Facade(){
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}
~Facade(){
delete one;
delete two;
delete three;
delete four;
}
void MethodA(){
cout<<"----方法组A----"<<'\n';
one->MethodOne();
two->MethodTwo();
four->MethodFour();
}
void MethodB(){
cout<<"----方法组B-----"<<'\n';
two->MethodTwo();
three->MethodThree();
}
private:
SubSystemOne* one;
SubSystemTwo* two;
SubSystemThree* three;
SubSystemFour* four;
};
int main(){
Facade* facade = new Facade();
facade->MethodA();
facade->MethodB();
delete facade;
return 0;
}
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以通过一个全局变量使得一个对象被访问,但不能防止实例化多个对象。一个最好的办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且可以提供一个访问该实例的方法。
懒汉式
单例实例在第一次被使用时才进行初始化
class Singleton{
private:
Singleton(){}
static Singleton* Instance;
public:
static Singleton* GetInstance(){
if(Instance == nullptr){
Instance = new Singleton();
}
return Instance;
}
};
改进版懒汉式(双重检查锁)
class Singleton{
private:
Singleton(){}
static Singleton* Instance;
public:
static Singleton* GetInstance(){
if(Instance == nullptr){
Lock();
if(Instance == nullptr){
Instance = new Singleton();
}
Unlock();
}
return Instance;
}
};
饿汉式
单例实例在程序运行时被立即执行初始化
class Singleton{
private:
Singleton(){}
~Singleton(){}
public:
static Singleton* GetInstance(){
static Singleton Instance;
return &Instance;
}
};
观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
适配器模式
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
// 目标抽象类
class Robot{
public:
virtual void eat() = 0;
virtual void sleep() = 0;
};
// 适配者类
class Douya{
public:
void eat(){ cout<<"豆芽吃饭"<<'\n'; }
void sleep(){ cout<<"豆芽睡觉"<<'\n'; }
};
// 适配器类
class RobotA : public Robot, public Douya{
public:
void eat(){
cout<< "机器人模仿:";
Douya::eat();
}
void sleep(){
cout<< "机器人模仿:";
Douya::sleep();
}
};