C++学习简单工厂模式
首先,明确一点,简单工厂模式属于创建型模式,但不属于GoF的23种模式;
简单工厂模式的定义: 根据传入的参数即可返回需要的对象,而不需要知道具体的类名;
简单说明:就是根据传入的参数返回可能的类的具体实例,通常工厂返回的类都具有一个公共的方法和父类;而工厂是什么?就是产生实例类的工厂类,将对象的创建和使用分离开来;
简单举例:如果你想吃水果,比如香蕉,现在有两种获取的方法,一种是自己种香蕉树,另外一种是直接购买现成的香蕉,你会选择哪一个?而工厂类的作用就是生产你想吃的水果,直接交给你成品,你不需要知道香蕉的产生过程;
小结简单工厂模式特点:负责生产需要的对象的实例,需要对参数进行判断,需要有公共的方法和共同的父类;
下面我们用C++模拟(Java模拟和C++不同,毕竟主攻C++,所以使用C++实现代码)
简单工厂模式C++代码实例
#include<iostream>
#include<string.h>
using namespace std;
class TV //共有的父类
{
public:
//公共的方法
virtual void tv() = 0; //纯虚函数使基类变为抽象类
//如果不使用虚函数或者纯虚函数,会发生切片;
/*
void tv()
{
//则最终结果会是这样
cout<<"TV"<<endl;
}
*/
};
class Hair:public TV
{
public:
void tv()
{
cout<<"Hair"<<endl;
}
};
class TCL:public TV
{
public:
void tv()
{
cout<<"TCL"<<endl;
}
};
class Factory
{
public:
//需要对传入参数进行判断,静态工厂方法
static TV* product(char* str)
{
//根据需要返回对应实例
if(strcmp(str,"Hair") == 0)
return new Hair();
else if(strcmp(str,"TCL") == 0)
return new TCL();
else
throw 0;
}
};
int main()
{
TV* tv;
try
{
tv = Factory::product("Hair");
tv->tv();
tv = Factory::product("TCL");
tv->tv();
tv = Factory::product("LOL");
tv->tv();
}
catch(...)
{
cout<<"不知名电视机"<<endl;
}
return 0;
}
分析:
首先,我们定义了一个抽象基类 TV:
class TV //共有的父类
{
public:
//公共的方法
virtual void tv() = 0; //纯虚函数使基类变为抽象类
//如果不使用虚函数或者纯虚函数,会发生切片;
/*
void tv()
{
//则最终结果会是这样
cout<<"TV"<<endl;
}
*/
};
在使用C++模拟时,需要将共有的方法变为虚函数或者纯虚函数,纯虚函数的话更像Java的interface; 如果不这样做,则会产生切片,所谓切片,就是在用父类的指针指向子类时,只会截取到属于父类的部分;
接下来,我们将需要生产的电视机品牌封装成类,并提供抽象基类中纯虚函数的定义;例如TCL
class TCL:public TV
{
public:
void tv()
{
cout<<"TCL"<<endl;
}
};
其中定义了父类的纯虚函数 tv;
接着就可以在使用时,告诉工厂类,我想要电视,而且想看的是TCL品牌的电视; 那么此时只需要传入TCL参数,工厂就会返回一个TCL电视的实例;如果想看Hair电视,就会返回Hair电视的实例,如果想看LOL电视,那么抱歉,没有这个品牌的电视; 当然,如果真的想看LOL品牌的电视,也可以创建一个LOL电视类,再对工厂方法进行修改即可!
下面是对mian函数的测试结果:
简单工厂模式是设计模式中比较简单的,和上一篇文章介绍的单例模式差不多;学习简单工厂模式是为了学习后面的工厂方法模式和抽象工厂模式打好基础;
简单工厂模式的优点
- 工厂类含有必要的逻辑判断,可以决定在什么时候创建哪个对象;
- 客户端无需知道所创建的具体的产品类的类名,只要知道具体产品类对应的参数即可;
- 可以在不修改客户端代码的情况下,进行更换和修改;
简单工厂模式的缺点
- 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,真个系统都会受到影响;
- 使用简单工厂模式会增加系统中类的个数(类泛滥),一定程度上增加系统的复杂度和理解难度;
- 系统扩展困难,一旦增加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护;
- 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构;例如:
#include<iostream>
using namespace std;
class A
{
public:
static void fun()
{
cout<<"A"<<endl;
}
};
class B:public A
{
public:
static void fun()
{
cout<<"B"<<endl;
}
};
int main()
{
A* demo;
demo = new B;
demo->fun();
system("pause");
return 0;
}
这样的话,输出的结果是 “A”,而不是期望的“B”;即子类无法覆盖继承自基类的静态方法;
模式适用场景
- 工厂类负责创建的对象比较少,这样的话,对象类就比较少,不会类泛滥;
- 客户端只需要知道传入工厂类的参数,不需要知道对象创建的细节的情况;