工厂方法模式引导

xiaoxiao2021-02-28  18

GOF四人帮的面向对象设计模式23种前言即为创建型设计模式抽象工程模式,本人看了很久没有很好理解,前段时间偶尔看到一个视频教程使用了一个工厂类来创建不同的对象的方法称之为简单工厂模式引出四人帮的抽象工厂模式与工厂方法模式。这里分享给大家。如下的例子称之为“简单工厂模式”并非属于设计模式之一。如下例子是厂商生产FiscalDisk的例子,之所以不用教材的例子而是重写例子也是为了更好的理解设计模式。

// SimpleFatroy.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" //int _tmain(int argc, _TCHAR* argv[]) //{ // return 0; //} //包含必要的头文件 #include <iostream> #include <assert.h> /* 直接看工厂方法模式不容易理解,为此特增加此模式来很好的引出23种的工厂方法与抽象工厂模式 此模式不属于GOF四人帮的23种设计模式之一。 */ class FiscalDiskBase { public: virtual ~FiscalDiskBase(){} virtual void PrintName() { printf("FiscalDisk生产厂商:%s\n", m_strName.c_str()); } protected://之所以用保护就是为了FiscalDiskBase不能被实例化 //默认构造函数为保护访问级别 //意味着FiscalDiskBase 不能被实例化必须继承 FiscalDiskBase(){}//无参构造 FiscalDiskBase(const std::string & name) :m_strName(name){ }//有参构造 std::string m_strName;//FiscalDisk厂商名称 }; //生产同一种产品有多家 //爱信诺 class AisinoFiscalDisk :public FiscalDiskBase { public: AisinoFiscalDisk() :FiscalDiskBase("爱信诺航天信息") { } void PrintName() { printf("Aisin Text \n"); FiscalDiskBase::PrintName(); } }; //宏思 class HSFiscalDisk :public FiscalDiskBase { public: HSFiscalDisk() :FiscalDiskBase("百旺金穗") { } void PrintName() { printf("HS Text \n"); FiscalDiskBase::PrintName(); } }; //国家信息安全技术研究中心(National Information Security Engineering Center) class NisecFiscalDisk :public FiscalDiskBase { public: NisecFiscalDisk() :FiscalDiskBase("国家安全总局") { } void PrintName() { printf("Nisec Text \n"); FiscalDiskBase::PrintName(); } }; //工厂 class FiscalDiskFactory { public: static FiscalDiskBase* Create(const std::string & name) { FiscalDiskBase * Card = NULL; if ("Aisic" == name) Card = new AisinoFiscalDisk(); //new 一个无参构造 else if ("HS" == name) Card = new HSFiscalDisk(); else if ("Nisec" == name) Card = new NisecFiscalDisk(); else assert(false);//异常处理 如果不是上面的三个名称则弹出错误对话框 return Card; } }; //测试函数 void SimpleFactory() { FiscalDiskBase* Card = FiscalDiskFactory::Create("Aisic"); Card->PrintName(); delete Card; Card = FiscalDiskFactory::Create("HS"); Card->PrintName(); delete Card; Card = FiscalDiskFactory::Create("Nisec"); Card->PrintName(); delete Card; } int main(void) { SimpleFactory(); getchar(); } /* 简单工厂模式:定义了一个穿件对象对象的接口 (FiscalDiskFactory), 根据所提供的参数决定创建出哪一个实体类的一个实例。简单工厂 模式封装了对象的创建过程。 由于创建函数为静态函数所以也有人取别名为静态工厂。

如下类图可以看出 ,Factory工程创建产品(ConcreateProduct ),而产品属于抽象的AbstractProduct 它里面有个操作printName,可以有很多个操作。产品可以有个所以都继承抽象的AbstractProduct。

可以看出测试用例中printName函数中,利用多态性掉了自己的printName然后显示的执行基类的printName。

为什么要用这种简单的工程模式?

答:为了提高高内聚(即类的接口或函数职责单一,有内聚性)松耦合(即类与类之间关系尽量的少)。其实我们经常抽象出一些类的公共接口已形成抽象基类或接口,这样可以声明一个指向基类的指针指向实际子类的实现从而达到多态的目的。即用了多态。但是这种方法很容易产生了2个问题。也就是上面的用了多态后大量的子类继承自抽象基类,我们不得不再每次使用到子类的地方写上new XXX();的代码,就是我们上面代码中工程类FiscalDiskFactory 里面的创建函数,里面就得添加new  对象,这样带来2个问题:

1、客户程序员必须知道子类的名称,当系统复杂时,为了处理可能的名字冲突,可能使用不具有很好的可读性和可记忆性的名字。很多子类太多了 我们可能使用了一堆很长的类名称以防止名字冲突,(我们例子当中简单工厂如使用了别名  缩写名参数化创建的实例化了某一个对象)。

2、程序的扩展和可维护性越来越困难。大量的new  不容易查找。(我们例子当中简单工厂提供一个函数里面集中了所有的new实例化对象容易查找)

所以这就是上面的简单工厂解决的问题。通过定义创建对象的接口,封装对象的创建,与客户端程序员无关,增强了程序的可扩展性Extension 及可维护性。(可扩展性其实并不是很强只是相对不使用这种方法要好很多)

Extension扩展性这里解释下是不需要修改你的代码只需要增加 (如果通过继承) 对象的组合方式,你不要使用类库的源代码这种情况下我们称之为扩展。

modification修改性这里是必须修改源代码才能够实现一些功能。

对于很多类库都是第三方库商业库不提供源代码就提供一个头文件和一个dll库,这种情况下你没有源代码既没有办法进行源码级别的修改。这个时候如果这商业代码做的不好那么我们就会很痛苦,所以对于面向对象来说有一个很重要的事情就是让程序具有扩展性意味着只需增加不需要修改源码。

我们例子当中的主要是有3个类:

1、FiscalDiskBase 定义所创建的产品接口

2、AisinoFiscalDisk、HSFiscalDisk、NisecFiscalDisk 这3个产品类实现接口。

3、FiscalDiskFactory 定义了一个方法,内部创建实际的产品并返回基类地址。

这种简单工厂方法适用于工具包或框架的开发。

这种方法有如下优缺点:

优点:工厂类是整模式的关键,包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建那个具体类的对象通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的,明确了各自的职责和权利,有利于整个软件体系结构的优化(这主要是针对用户的优点)。

缺点:

由于上面的简单工厂类集中了所有实例的创建逻辑,违反了高内聚责任的分配原则,将全部创建逻辑集中到一个工厂类中;它所能创建的类也只能是事先考虑到的,如果需要增加新类,则就需要改变工厂类了。(当然据说hook可以解决但这不符合面向对象的概念)当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同的实例需求,这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。

而这些缺点在以后的23种设计模式中的工厂方法模式中得到一定的克服解决。

转载请注明原文地址: https://www.6miu.com/read-2630329.html

最新回复(0)