看了大话设计模式一书第二遍了,有新的体会,现将其总结一下
1.简单工厂模式
应该是最简单的设计模式了,在实际应用中如果多个对象的操作有相同的逻辑,只是实现的细节不同,那么可以考虑利用简单工厂模式。例如加减乘
除同样都是运算符,需要对两个数进行计算然后输出一个结果,这里可以将其抽象出四个类。根据不同的要求实例化出不同的运算符类。在我之前做的一
个项目中,需要根据点击下拉框中选中对象不同的Text来创建不同的Form去处理我就使用了简单工厂模式。这样可以做到代码的可维护性和和可扩展性增
强。
2.工厂模式
在简单工厂模式中,根据不同的TEXT去判断生成哪一个类。这样当我们新增加一个类的时候就要到工厂类里面去加必要的判断生成哪一个类,这样是
简单,但是违背了面向对象设计中的开放封闭原则---对于新增的需求,对于扩展是开放的,对于修改则是封闭的。意思就是说要新增类的话新增加一个类就
可以了不用改动原来的代码。工厂模式就是为了克服这个缺点提出的。为了实现一个新的功能,我们只需要在工厂的类中新添加若干新类newFactory,然后
在调用的时候Factory fa=new newFactory()即可,这样就保持了开放封闭原则。
3.抽象工厂方法
抽象工厂与简单工厂和工厂模式最大的区别在与,工厂模式和简单工厂模式生成的产品只有一种,而抽象工厂类则可以生成多种不同的产品。打个比方
如果工厂方法可以生成不同的内存,那么抽象工厂就可以生成一台电脑,是的,他可以生成不同型号的主板、CPU、GPU硬盘等等,然后再将其组合成一台
电脑。意味着它里面又包含了主版工厂、CPU工厂这些需要组成一台电脑相互的产品工厂。完成了更高层次上的抽象。但是他也有它的不足,每当我们要新
增加一个电脑部件产品工厂的时候这就需要修改目前所有的电脑工厂类,将这个新功能加进去,修改量是很大的。以生产一台电脑为例:
#include <iostream>
#include <string>
using namespace std;
class iCPU
{
public:
virtual void getinfo()=0;
virtual void compute()=0;
};
class iGPU
{
public:
virtual void getinfo()=0;
virtual void compute()=0;
};
class IFactory
{
public:
virtual iCPU* CreateCPU()=0;
virtual iGPU* CreateGPU()=0;
};
class CPUA:public iCPU
{
public:
virtual void getinfo()
{
cout<<"我是因特尔处理器"<<endl;
}
virtual void compute()
{
cout<<"执行计算"<<endl;
}
};
class GPUA:public iGPU
{
public:
virtual void getinfo()
{
cout<<"我是Nivida显卡"<<endl;
}
virtual void compute()
{
cout<<"图像计算"<<endl;
}
};
class ComputorA:public IFactory
{
public:
virtual CPUA* CreateCPU()
{
return new CPUA();
}
virtual GPUA* CreateGPU()
{
return new GPUA;
}
};
int main()
{
IFactory* cmpA=new ComputorA();
iCPU *cpu=cmpA->CreateCPU();
iGPU *gpu=cmpA->CreateGPU();
cpu->getinfo();
cpu->compute();
gpu->getinfo();
gpu->compute();
}
4.单例模式
同样将我之前的那个WinForm作为例子,我在程序运行的时候如果多次点击创建选项,那马就会创建出许多的实例,这样既不美观也浪费资源。如果
只想一个对象只有一个实例,那么久可以考虑单例模式了,它只允许一个类创建一个实例。具体的做法是将那个Form的构造函数声明为private。这样程
序就不能显式的调用其构造函数了,如果希望获得类的一个实例那么就要通过类的静态成员方法GetInstance(),在这个类的对象中有一指向自己类实例的
指针,这个方法会判断这个指针是否为空,如果是就新建一个类对象将其返回,如果不是就直接返回指向的对象,这样就达到了只有一个实例的目的。在多
线程的环境就要注意了,尽量写成以下形式,既可以避免每次检查都加锁,又可以保证只有一个实例。
if(ptr==null)
{
if(GetLock)
{
if(ptr==null)
{
return GetInstance();
}
}
}
else
return ptr;
5. 装饰者模式
在完成一个任务中,有许多细节要处理,而这些细节没有严格的次序,是一些步骤的任意组合,那么就可以用装饰者模式了。
在装饰者模式中所有类都继承一个父类Component它有一个Operation()方法,负责完成它的核心职责逻辑。装饰类都继承于他,每个装饰类中都
有一个Operation()方法和一个Component指针。然后有若干新添加的方法以及属性,实现如下
class Decrator :public Component
{
protected:
Component *p;
public:
void Decrator(Component *PER)
{
p=PER;
}
virtual void show()
{
if(p!=NULL)
p->show();
}
};
在继承被装饰的对象后,具体的装饰类然后继承该装饰类可以添加自己新增的属性和方法,每个类先调用父类的Operation(),然后再完成自己的任务,
层层装饰,最后达到将使用和装饰实现分离的目的。
6.适配器模式
有时候两个类需要完成的功能或者说逻辑是一样的,但是他们在各自类中的方法不一样,那么这个时候我们就需要适配器模式了。
7. 建造者模式
在我们开发中如果有时候要完成的任务是步骤一定的,每一步实现可能有所差别,这个时候就是建造者模式派上用场的地方了。我们可以把要完成的
步骤抽象为一个抽象类,把要完成的步骤固定下来,这样就就不会遗漏任何一个步骤(因为包含纯虚函数的类是不能实例化的)。以游戏中我们要建造一个人
物模型为例。人物模型都有头、身体、手、脚等,这些都是一样的,那么就可以将这些过程抽象出来,形成一个抽象类,里面包含构造各个部位的方法。然
为了隔绝调用者和建造过程的关系(当我们构造的顺序有变动的时候我们直接到建造者中修改即可,不用修改所有调用的地方),我们可以设定一个建造指挥
者,由它将建造好的对象直接返回即可。下面是一个例子。
#include <iostream>
using namespace std;
class BuildPerson
{
public:
virtual void BuildHead()=0;
virtual void BuildBody()=0;
virtual void BuildHand()=0;
virtual void BuildLeg()=0;
};
class Person : public BuildPerson
{
public:
virtual void BuildHead()
{
cout<<"建造头部"<<endl;
}
virtual void BuildBody()
{
cout<<"建造身体"<<endl;
}
virtual void BuildHand()
{
cout<<"建造手臂"<<endl;
}
virtual void BuildLeg()
{
cout<<"建造双脚"<<endl;
}
};
class PersonDirector
{
private:
BuildPerson* bp;
public:
PersonDirector(BuildPerson* b)
{
bp=b;
}
void GetPerson()
{
bp->BuildBody();
bp->BuildLeg();
bp->BuildHead();
bp->BuildHand();
}
};
int main()
{
PersonDirector pd(new Person);
pd.GetPerson();
}