[C++实现 设计模式(2)] : 工厂方法模式

16 篇文章 0 订阅

工厂方法模式的定义

       首先需要说一下工厂模式 , 工厂模式根据抽象程度的不同分为三种简单工厂模式(也叫静态工厂模式)、工厂方法模式、以及抽象工厂模式 .
定义 : 定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类 .

工厂方法模式通用类图(UML):
在这里插入图片描述

通过工厂方法模式的类图可以看到,工厂方法模式有四个要素

  • 工厂接口 . 工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品 . 在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的 .
  • 工厂实现 . 在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现 .
  • 产品接口 . 产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范 . 产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性 . 同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则 .
  • 产品实现 . 实现产品接口的具体类,决定了产品在客户端中的具体行为 .

       简单工厂模式跟工厂方法模式极为相似,区别是简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的 . 因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算所工厂方法模式的简化版,关于简单工厂模式,将在下文讲解 .

场景说明

       女娲要造三种不同肤色的人 , 女娲采集黄土捏成人形 , 然后放到八卦炉中烧制 , 最后放置在大地上生长 . 首先对造人的过程进行分析 , 该过程设计三个对象 : 女娲 , 八卦炉 , 三种不同肤色的人 .女娲可以使用Client来表示 , 八卦炉类似于一个工厂 , 负责制造生产产品(即人类) , 三种不同肤色的人 , 他们都是同一个接口下的不同实现类 . 设置专门的工厂用来生产黑色人种 , 设置专门的工厂用来生产黄色人种 , 再设置专门的工厂用来生产白色人种 . 这时 , 女娲想造什么肤色的人 , 就到专门的工厂 .

类图(UML)如下 :

在这里插入图片描述

代码如下 :

//工厂方法模式
#if 0
class Human
{
public:
	virtual void show() = 0;
};
//黑色人种
class BlackHuman : public Human
{
public:
	void show()
	{ cout<<"BlackHuman"<<endl; }
};

//黄色人种
class YellowHuman : public Human
{
public:
	void show()
	{ cout<<"YellowHuman"<<endl; }
};

//白色人种
class WhiteHuman : public Human
{
public:
	void show()
	{ cout<<"WhiteHuman"<<endl; }
};
//工厂
class HumanFactory
{
public:
	virtual  Human* CreateHuman() = 0;
};
//黑色人种工厂
class BlackFactory : public HumanFactory
{
public:
	BlackHuman* CreateHuman()
	{ return new BlackHuman() ; }
};

//黄色人种工厂
class YellowFactory : public HumanFactory
{
public:
	YellowHuman* CreateHuman()
	{ return new YellowHuman() ; }
};

//白色人种工厂
class WhiteFactory : public HumanFactory
{
public:
	WhiteHuman* CreateHuman()
	{ return new WhiteHuman() ; }
};

int main()
{
	HumanFactory* human = new BlackFactory();
	Human* _humanA = human->CreateHuman();
	_humanA->show();	

	//释放内存 , 防止内存泄漏
	delete human;
	human = nullptr;
	delete _humanA;

	human = new YellowFactory();
	Human* _humanB = human->CreateHuman();
	_humanB->show();	
	delete human;
	human = nullptr;
	delete _humanB;

	human = new WhiteFactory();
	Human* _humanC = human->CreateHuman();
	_humanC->show();
		
	delete human;
	human = nullptr;
	delete _humanC;

	return 0;
}

#endif

运行结果 :
在这里插入图片描述

工厂方法模式的应用

工厂方法模式是编程中经常用到的一种模式 .它的主要优点有

  • 良好的封装性 , 可以使代码结构清晰 .在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品 .
  • 对调用者屏蔽具体的产品类 .如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响.
  • 工厂方法模式是典型的解耦框架 .高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流 ; 也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类 .
  • 工厂方法模式的扩展性非常优秀 . 在增加产品类的情况下 , 只要适当地修改具体的工厂类或扩展一个工厂类 , 就可以完成 “拥抱变化” .

工厂方法模式的使用场景

       首先,工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度 .
       其次,需要灵话的、可扩展的框架时,可以考虑采用工厂 方法模式 . 万物皆对象,那万物也就皆产品类,例如需要设计一个连接邮件服务器的框架,有三种网络协议可供选择: POP3 , IMAP , HTTP, 我们就可以把这三种连接方法作为产品类,定义一个接口如IConnectMail,然后定义对邮件的操作方法,用不同的方法实现三个具体的产品类(也就是连接方式)再定义一个工厂方法,按照不同的传入条件,选择不同的连接方式 . 如此设计,可以做到完美的扩展,如某些邮件服务器提供了WebService接口,我们只要增加一一个产品类就可以了 .
       再次,工厂方法模式可以用在异构项目中,例如通过WebService与一个非Java的项目交互,虽然WebService号称是可以做到异构系统的同构化,但是在实际的开发中,还是会碰到很多问题,如类型问题、WSDL文件的支持问题,等等 . 从WSDL中产生的对象都认为是一个产品,然后由一个具体的工厂类进行管理,减少与外围系统的耦合 .
       最后,可以使用在测试驱动开发的框架下 . 例如,测试一个类A,就需要把与类A有关联关系的类B也同时产生出来,我们可以使用工厂方法模式把类B虚拟出来,避免类A与类B的耦合 .

工厂方法模式的扩展

简单工厂模式

       它的主要特点是 : 需要在工厂类中做判断,从而创造相应的产品 . 当增加新的产品时,就需要修改工厂类 . 接着女娲造人的例子来说 , 在八卦炉(工厂)中 , 能够生产的只有三种肤色的人(黑,黄,白) , 女娲(客户)需要造什么肤色的人 , 一定要显式的告诉八卦炉(工厂) .

类图(UML)如下 :
在这里插入图片描述

代码如下:

//简单工厂模式
 #if 0
enum CTYPE {Black,Yellow,White};
class Human
{
public:
	virtual void show() = 0;
};
//黑色人种
class BlackHuman : public Human
{
public:
	void show()
	{ cout<<"BlackHuman"<<endl; }
};

//黄色人种
class YellowHuman : public Human
{
public:
	void show()
	{ cout<<"YellowHuman"<<endl; }
};

//白色人种
class WhiteHuman : public Human
{
public:
	void show()
	{ cout<<"WhiteHuman"<<endl; }
};

//唯一的工厂 , 可以生产三种不同种类的人
class HumanFactory
{
public:
	Human* CreateHuman(enum CTYPE ctype)
	{
		if(ctype == Black)//工厂内部判断
		{
			//生产黑色人种
			return new BlackHuman();
		}
		else if(ctype == Yellow)
		{
			//生产黑黄色人种
			return new YellowHuman();
		}
		else if(ctype == White)
		{
			//生产白色人种
			return new WhiteHuman();
		}
		else
		{
			return nullptr;
		}
	}
};

int main()
{
	HumanFactory humanfactory;
    //显示告诉工厂造什么肤色的人
	Human* _humanA = humanfactory.CreateHuman(Black);
	_humanA->show();

	Human* _humanB = humanfactory.CreateHuman(Yellow);
	_humanB->show();

	Human* _humanC = humanfactory.CreateHuman(White);
	_humanC->show();

	//释放内存 , 防止内存泄漏
	delete _humanA;
	delete _humanB;
	delete _humanC;
	return 0;
}

#endif

运行结果 :
在这里插入图片描述

参考书籍 :

                  <<设计模式之禅 第二版>>
                  <<设计模式>>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值