设计模式存在的目的是使人们可以更加简单方便地复用成功的设计和体系结构。为了可重用代码、让代码更容易被他人理解、保证代码可靠性,可维护性。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式使代码编制真正工程化,它是软件工程的基石,如同大厦的第一块块砖石一样。不理解设计模式就不能说精通面向对象编程思想,就不能说是一名合格的C++码农。
设计模式而为了代码复用,增加代码可维护性而生,而要做到这些的基本原则就是:开闭原则(Open Closed Principal,OCP)、里氏代换原则(Liskov Substitution Principle,LSP)、依赖倒转原则(Dependency Inversion Principle,DIP)、接口隔离原则(Interfce Segregation Principle,ISP)、合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)、最小知识原则(Principle of Least Knowledge,PLK,也叫迪米特法则)。开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。其他几条,则可以看做是开闭原则的实现方法。设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。
GOF设计模式将其分为三种类型,共23种(当然个人认为好的设计都可以抽象提炼成为模式,它体现的只是一种优秀的设计思路、编程思想)。
1.创建型模式:单件模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
2.结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3.行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
一、Factory 模式(工厂模式)
1.存在意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。专门创建一个类来负责创建其他类的实例,被创建的实例往往具有相同的父类或接口。属于类的创建型模式,通常根据一个条件(参数)来返回不同的类的实例。
它还可以被分为三类
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
这三类从上到下逐步抽象。在GOF《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
2.组成元素:
1) 简单工厂模式
工厂角色(Creator):整个简单工厂模式的核心,负责实现创建所有具体产品类的实例。可以被外界直接调用,创建所需的产品对象。含有一定的商业逻辑和判断逻辑。
抽象产品角色(Product):是所有具体产品角色的父类,它负责描述所有实例所共有的公共接口。
具体产品角色(Concrete Product):继承自抽象产品角色,一般为多个,是简单工厂模式的创建目标。工厂类返回的都是该角色的某一具体产品。
例子:假设我的计算机很牛X能随时更换CPU,我现在有一块单核的正在使用。
实现:(以Win32控制台程序为例)
//Factory.h
#pragma once
class CPU
{
public:
virtual void Run() = 0;
};
class SingleCore :public CPU
{
public:
void Run();
};
class CFactory
{
public:
CPU *CreateSingleCPU();
};
//Factory.cpp
#include "StdAfx.h"
#include "Factory.h"
#include <iostream>
using namespace std;
void SingleCore::Run()
{
cout<<"SingleCoreRun"<<endl;
}
CPU *CFactory::CreateSingleCPU()
{
return new SingleCore();
}
//main.cpp
#include "stdafx.h"
#include "Factory.h"
int _tmain(int argc, _TCHAR* argv[])
{
CFactory mFactory;
CPU *pCPU = NULL;
pCPU = mFactory.CreateSingleCPU();
pCPU->Run();
while(1);
return 0;
}
现在我又购买了一块双核和一块四核的CPU(假设主板都能够支持),想换一块试试。那么就需要对代码进行维护了
//Factory.h
#pragma once
class CPU
{
public:
virtual void Run() = 0;
};
class SingleCore :public CPU
{
public:
void Run();
};
class DoubleCore :public CPU
{
public:
void Run();
};
class FourCore :public CPU
{
public:
void Run();
};
class CFactory
{
public:
CPU *CreateSingleCPU();
CPU *CreateDoubleCPU();
CPU *CreateFourCPU();
};
//Factory.cpp
#include "StdAfx.h"
#include "Factory.h"
#include <iostream>
using namespace std;
void SingleCore::Run()
{
cout<<"SingleCoreRun"<<endl;
}
void DoubleCore::Run()
{
cout<<"DoubleCoreRun"<<endl;
}
void FourCore::Run()
{
cout<<"FourCoreRun"<<endl;
}
CPU *CFactory::CreateSingleCPU()
{
return new SingleCore();
}
CPU *CFactory::CreateDoubleCPU()
{
return new DoubleCore();
}
CPU *CFactory::CreateFourCPU()
{
return new FourCore();
}
//main.cpp
#include "stdafx.h"
#include "Factory.h"
int _tmain(int argc, _TCHAR* argv[])
{
CFactory mFactory;
CPU *pCPU = NULL;
pCPU = mFactory.CreateSingleCPU();
pCPU->Run();
pCPU = mFactory.CreateDoubleCPU();
pCPU->Run();
pCPU = mFactory.CreateFourCPU();
pCPU->Run();
while(1);
return 0;
}
或者:
#pragma once
typedef enum
{
SINGLE_CORE = 0,
DOUBLE_CORE,
FOUR_CORE
}CPU_TYPE;
class CPU
{
public:
virtual void Run() = 0;
};
class SingleCore :public CPU
{
public:
void Run();
};
class DoubleCore :public CPU
{
public:
void Run();
};
class FourCore :public CPU
{
public:
void Run();
};
class CFactory
{
public:
CPU *CreateCPU(CPU_TYPE eType);
};
#include "StdAfx.h"
#include "Factory.h"
#include <iostream>
using namespace std;
void SingleCore::Run()
{
cout<<"SingleCoreRun"<<endl;
}
void DoubleCore::Run()
{
cout<<"DoubleCoreRun"<<endl;
}
void FourCore::Run()
{
cout<<"FourCoreRun"<<endl;
}
CPU *CFactory::CreateCPU(CPU_TYPE eType)
{
switch (eType)
{
case SINGLE_CORE:
return new SingleCore();
case DOUBLE_CORE:
return new DoubleCore();
case FOUR_CORE:
return new FourCore();
default:
return new SingleCore();
}
}
#include "stdafx.h"
#include "Factory.h"
int _tmain(int argc, _TCHAR* argv[])
{
CFactory *pFac = new CFactory;
CPU *pCPU = pFac->CreateCPU(SINGLE_CORE);
pCPU->Run();
pCPU = pFac->CreateCPU(DOUBLE_CORE);
pCPU->Run();
pCPU = pFac->CreateCPU(FOUR_CORE);
pCPU->Run();
delete pFac;
while(1);
return 0;
}
这样的修改固然能够使用,对产品类也符合扩展开放,修改关闭原则,但是它对于工厂类并不符合开闭原则。若是以后出现更多核的,工厂类就需要一次次的修改业务逻辑。在这种情况下,工厂方法模式就体现出其优势了。
2)工厂方法模式(Factory Method)
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
抽象产品角色:它是具体产品继承的父类或者是实现的接口。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。
这种情况下将工厂类进行抽象,只需要增加响应的产品类和工厂类就可以,而不需要修改原有的逻辑代码。虽然有时候做的修改更多但是它在安全性和可维护性上的优势是相当明显的。
//Factory.h
#pragma once
class CPU
{
public:
virtual void Run() = 0;
};
class SingleCore :public CPU
{
public:
void Run();
};
class DoubleCore :public CPU
{
public:
void Run();
};
class FourCore :public CPU
{
public:
void Run();
};
class CFactory
{
public:
virtual CPU *CreateCPU()=0;
};
class FactorySingle:public CFactory
{
public:
CPU *CreateCPU();
};
class FactoryDouble:public CFactory
{
public:
CPU *CreateCPU();
};
class FactoryFour:public CFactory
{
public:
CPU *CreateCPU();
};
//Factory.cpp
#include "StdAfx.h"
#include "Factory.h"
#include <iostream>
using namespace std;
void SingleCore::Run()
{
cout<<"SingleCoreRun"<<endl;
}
void DoubleCore::Run()
{
cout<<"DoubleCoreRun"<<endl;
}
void FourCore::Run()
{
cout<<"FourCoreRun"<<endl;
}
CPU *FactorySingle::CreateCPU()
{
return new SingleCore();
}
CPU *FactoryDouble::CreateCPU()
{
return new DoubleCore();
}
CPU *FactoryFour::CreateCPU()
{
return new FourCore();
}
//main.cpp
#include "stdafx.h"
#include "Factory.h"
int _tmain(int argc, _TCHAR* argv[])
{
CFactory *pFac = new FactorySingle();
CPU *pCPU = pFac->CreateCPU();
pCPU->Run();
pFac = new FactoryDouble();
pCPU = pFac->CreateCPU();
pCPU->Run();
pFac = new FactoryFour();
pCPU = pFac->CreateCPU();
pCPU->Run();
while(1);
return 0;
}
这种情况要扩展的时候就只是增加而非修改以前的代码