加深理解设计模式的好资料,转自 http://blog.youkuaiyun.com/gatieme/article/details/17952033
(一)工厂模式描述
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
类型:创建类模式
用途:工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,降低耦合度
达到提高灵活性的目的。
类图:
现在一般看来将工厂模式分为三类:
1)简单工厂模式(Simple Factory)
2)工厂方法模式(Factory Method)
3)抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。
GOF在《设计模式》一书中将工厂模式分为两类:
工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。
将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
但是两种看法本质上是一致的,而且我们没必要深究那么多,下面来看看这些工厂模式是怎么来“治病”的。
工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。听上去差不多,都是工厂模式。
下面一个个介绍,首先介绍简单工厂模式,它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。有点抽象,
举个例子就明白了。有一家生产处理器核的厂家,它只有一个工厂,能够生产两种型号A,B的处理器核。不同的客户有不同的需求,有的客户喜欢A核,有的客户偏爱B核,怎么满足这种需求呢,
简单工厂,客户需要什么样的处理器核,一定要显示地告诉生产工厂。下面给出一种实现方案。
(二)简单工厂模式
简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口
先来看看它的组成
① 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。它往往由一个具体类实现。
② 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。
③ 具体产品角色:工厂类所创建的对象就是此角色的实例。由一个具体类实现。
#include <iostream>
// 生成产品依据标识
typedef enum ClassType
{
SINGCORE_A,
SINGCORE_B,
}ClassType;
////////////////////////////////////////////////////////////////////////////////
// 基础产品类 -=> 对应于抽象产品角色
class SingCore
{
public :
virtual ~SingCore( ){ }; // 虚析构函数
virtual void Show( ) = 0; // 产品的显示函数
};
// 单核产品S -=> 对应于具体产品角色
class SingCoreA : public SingCore
{
public :
virtual ~SingCoreA( ){ }; // 虚析构函数
void Show( )
{
std::cout <<"SingCore A..." <<std::endl;
}
};
// 单核产品B -=> 对应于具体产品角色
class SingCoreB : public SingCore
{
public :
virtual ~SingCoreB( ){ }; // 虚析构函数
void Show( )
{
std::cout <<"SingCore B..." <<std::endl;
}
};
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
// 工厂类 -=> 对应于工厂角色
class Factory
{
public :
virtual ~Factory( ){ }; // 虚析构函数
SingCore* CreateSingCore(ClassType classType)
{
switch(classType)
{
case SINGCORE_A :
{
return new SingCoreA( );
}
case SINGCORE_B :
{
return new SingCoreB( );
}
}
}
};
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
int main()
{
Factory *factory = new Factory( );
factory->CreateSingCore(SINGCORE_A)->Show( );
factory->CreateSingCore(SINGCORE_B)->Show( );
delete factory;
}
首先,使用了简单工厂模式后,我们的程序更加符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品,使客户端不再依赖与具体产品的创建,就像我们买产品A和产品B,我们只关心它是不是我们需要的产品,并不关心它是怎么被创建的。
但是这样设计的也有缺点,就是要增加新的核类型时,就需要修改工厂类。这就违反了开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员
于是工厂方法模式作为救世主出现了。
三 工厂方法模式
所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。
Factory Method工厂方法模式使一个类的实例化延迟到其子类。
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。
这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
你应该大致猜出了工厂方法模式的结构,来看下它的组成:
① 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。它由抽象类或者接口来实现。
② 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
③ 抽象产品角色:它是具体产品继承的父类或者是实现的接口。一般有抽象类或者接口来实现。
④具体产品角色:具体工厂角色所创建的对象就是此角色的实例。由具体的类来实现。
还是以刚才的例子解释。这家生产处理器核的产家赚了不少钱,于是决定再开设一个工厂专门用来生产B型号的单核,而原来的工厂专门用来生产A型号的单核。这时,客户要做的是找好工厂,比如要A型号的核,就找A工厂要;否则找B工厂要,不再需要告诉工厂具体要什么型号的处理器核了。
#include <iostream>
////////////////////////////////////////////////////////////////////////////////
// 核心产品基类 -=> 对应于抽象产品角色
class SingCore
{
public :
virtual ~SingCore( ){ }; // 虚析构函数
virtual void Show( ) = 0; // 产品显示函数
};
// 核心产品A -=> 对应于具体产品角色
class SingCoreA : public SingCore
{
public :
virtual ~SingCoreA( ){ }; // 虚析构函数
void Show( ) // 产品显示函数
{
std::cout <<"SingCore A..." <<std::endl;
}
};
// 核心产品B -=> 对应于具体产品角色
class SingCoreB : public SingCore
{
public :
virtual ~SingCoreB( ){ }; // 虚析构函数
void Show( ) // 产品显示函数
{
std::cout <<"SingCore B..." <<std::endl;
}
};
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
// 工厂的基类 -=> 对应于抽象工厂角色
class Factory
{
public:
virtual ~Factory( ){ }; // 虚析构函数
virtual SingCore* CreateSingCore( ) = 0; // 生产产品的生产线
};
// 生产核心A的工厂 -=> 对应于具体产品角色
class FactoryA : public Factory
{
public :
virtual ~FactoryA( ){ }; // 虚析构函数
SingCoreA* CreateSingCore( )
{
return new SingCoreA( );
}
};
// 生产核心B的工厂 -=> 对应于具体产品角色
class FactoryB : public Factory
{
public :
virtual ~FactoryB( ){ }; // 虚析构函数
SingCoreB* CreateSingCore( )
{
return new SingCoreB( );
}
};
int main( )
{
Factory *factoryA = new FactoryA( );
factoryA->CreateSingCore( )->Show( );
Factory *factoryB = new FactoryB( );
factoryB->CreateSingCore( )->Show( );
return 0;
}
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。可以看出工厂角色的结构也是符合开闭原则的!就相当于市面上同样的产品有很多个牌子,有A牌子和B牌子,每家都有一个单独的工厂用来生产。这样每次增加一个新的牌子的产品上市,都会有一家新的工厂出现。
五 抽象工厂模式
好了那到底什么是抽象工工厂呢,它到底有什么作用呢?
在将抽象工厂前我们先来认识一下产品族。
还是举这个例子,这家公司的技术不断进步,不仅可以生产单核处理器,也能生产多核处理器。每个处理器下都有A,B两种型号的。那么这里A单核和B单核就同属于一个单核产品族。A多核和B多核就同属于一个多核产品族。
对于这种情况,就需要用到抽象工厂了。它的定义为提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。具体这样应用,这家公司还是开设两个工厂,一个专门用来生产A型号的单核多核处理器,而另一个工厂专门用来生产B型号的单核多核处理器,每个工厂用来生产一个产品族。
抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象
而且使用抽象工厂模式还要满足一下条件:
①系统中有多个产品族,而系统一次只可能消费其中一族产品。
②同属于同一个产品族的产品以其使用。
看看抽象工厂模式的各个角色(和工厂方法的如出一辙):
①抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。它由抽象类或者接口来实现。
②具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。它由具体的类来实现。
③ 抽象产品角色:它是具体产品继承的父类或者是实现的接口。一般有抽象类或者接口来实现。
④具体产品角色:具体工厂角色所创建的对象就是此角色的实例。由具体的类来实现
抽象工厂模式和工厂方法模式的区别
可以说,抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。
你能见到的大部分抽象工厂模式都是这样的:它的里面是一堆工厂方法,每个工厂方法返回某种类型的对象。
如果说抽象工厂中的工厂是一个实际的工厂的话,那么工厂方法中的工厂更像现实中工厂的一条生产线
下面举个例子具体描述一下①比如说工厂可以生产鼠标和键盘。那么抽象工厂的实现类(它的某个具体子类)的对象都可以生产鼠标和键盘,但可能工厂A生产的是罗技的键盘和鼠标,工厂B是微软的。这样A和B就是工厂,对应于抽象工厂;每个工厂生产的鼠标和键盘就是产品,对应于工厂方法;用了工厂方法模式,你替换生成键盘的工厂方法,就可以把键盘从罗技换到微软, 但是鼠标还是原来罗技的但是用了抽象工厂模式,你只要换家工厂,就可以同时替换鼠标和键盘一套。如果你要的产品有几十个,当然用抽象工厂模式一次替换全部最方便(这个工厂会替你用相应的工厂方法)所以说抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线,
抽象工厂模式适合与如下的情况
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类可以创建多个具体产品类的实例。
下面附上抽象工厂的代码
#include <iostream>
////////////////////////////////////////////////////////////////////////////////
//单核产品类族
////////////////////////////////////////////////////////////////////////////////
// 单核产品基类
class SingleCore
{
public:
virtual void Show( ) const = 0;
};
// 单核A
class SingleCoreA: public SingleCore
{
public:
void Show( )const
{
std::cout<<"SingleCore A"<<std::endl;
}
};
// 单核B
class SingleCoreB: public SingleCore
{
public:
void Show( ) const
{
std::cout<<"SingleCore B"<<std::endl;
}
};
////////////////////////////////////////////////////////////////////////////////
// 多核产品类族
////////////////////////////////////////////////////////////////////////////////
// 多核产品类族基类
class MultiCore
{
public:
virtual void Show( ) const = 0;
};
// 多核产品A
class MultiCoreA : public MultiCore
{
public:
void Show() const
{
std::cout<<"Multi Core A"<<std::endl;
}
};
// 多核产品B
class MultiCoreB : public MultiCore
{
public:
void Show( ) const
{
std::cout<<"Multi Core B"<<std::endl;
}
};
// 工厂
class Factory
{
public:
virtual SingleCore* CreateSingleCore( ) = 0;
virtual MultiCore* CreateMultiCore( ) = 0;
};
// 工厂A,专门用来生产A型号的处理器
class FactoryA :public Factory
{
public:
SingleCore* CreateSingleCore( )
{
return new SingleCoreA( );
}
MultiCore* CreateMultiCore( )
{
return new MultiCoreA( );
}
};
// 工厂B,专门用来生产B型号的处理器
class FactoryB : public Factory
{
public:
SingleCore* CreateSingleCore()
{
return new SingleCoreB( );
}
MultiCore* CreateMultiCore( )
{
return new MultiCoreB( );
}
};
int main()
{
// 生产产品A系列的产品工厂
FactoryA *factoryA = new FactoryA( );
factoryA->CreateSingleCore( )->Show( );
factoryA->CreateMultiCore( )->Show( );
// 生产B系列的产品工厂
FactoryB *factoryB = new FactoryB( );
factoryB->CreateSingleCore( )->Show( );
factoryB->CreateMultiCore( )->Show( );
}
简单工厂模式,工厂方法模式和抽象工厂模式都是属于创建型设计模式,这三种创建型模式都不需要知道具体类。我们掌握一种思想,就是在创建一个对象时,需要把容易发生变化的地方给封装起来,来控制变化(哪里变化,封装哪里),以适应客户的变动,项目的扩展。用这三种设计模式都可以实现,那究竟这三种设计模式有什么异同呢?下面根据这三者之间的特点,优点,缺点,适用范围进行比较。
一.特点
简单工厂模式:专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式。它的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。
工厂方法模式:工厂方法是粒度很小的设计模式,因为模式的表现只是一个抽象的方法。提前定义用于创建对象的接口,让子类决定实例化具体的某一个类,即在工厂和产品中间增加接口,工厂不再负责产品的创建,由接口针对不同条件返回具体的类实例,由具体类实例去实现。工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次实现更复杂的层次结构,可以应用于产品结果复杂的场合。工厂方法模式是对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
抽象工厂模式:抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。它有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类的实例。每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结果。
其中抽象工厂和工厂方法很类似,区别如下:
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个
二.优点
简单工厂模式:工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅"消费"产品。简单工厂模式通过这种做法实现了对责任的分割。简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过它,外界可以从直接创建具体产品对象的尴尬局面中摆脱出来。外界与具体类隔离开来,偶合性低。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。工厂方法模式:工厂方法模式是为了克服简单工厂模式的缺点(主要是为了满足OCP)而设计出来的。简单工厂模式的工厂类随着产品类的增加需要增加很多方法(或代码),而工厂方法模式每个具体工厂类只完成单一任务,代码简洁。工厂方法模式完全满足OCP,即它有非常良好的扩展性。
抽象工厂模式:抽象工厂模式主要在于应对“新系列”的需求变化。分离了具体的类,抽象工厂模式帮助你控制一个应用创建的对象的类,因为一个工厂封装创建产品对象的责任和过程。它将客户和类的实现分离,客户通过他们的抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,它们不出现在客户代码中。它使得易于交换产品系列。一个具体工厂类在一个应用中仅出现一次——即在它初始化的时候。这使得改变一个应用的具体工厂变得很容易。它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。它有利于产品的一致性。当一个系列的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要,而抽象工厂很容易实现这一点。抽象工厂模式有助于这样的团队的分工,降低了模块间的耦合性,提高了团队开发效率。
三.缺点
简单工厂模式:当产品有复杂的多层等级结构时,工厂类只有自己,以不变应万变,就是模式的缺点。因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂,违背了"开放--封闭"原则(OCP).另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构。工厂方法模式:不易于维护,假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦(对号入座已经是个问题了)。
抽象工厂模式:抽象工厂模式在于难于应付“新对象”的需求变动。难以支持新种类的产品。难以扩展抽象工厂以生产新种类的产品。这是因为抽象工厂几乎确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及抽象工厂类及其所有子类的改变。
四.适用范围
简单工厂模式:工厂类负责创建的对象比较少,客户只知道传入了工厂类的参数,对于始何创建对象(逻辑)不关心。工厂方法模式:当一个类不知道它所必须创建对象的类或一个类希望由子类来指定它所创建的对象时,当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候,可以使用工厂方法。
抽象工厂模式:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。这个系统有多于一个的产品族,而系统只消费其中某一产品族。同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
其实,无论是简单工厂模式、工厂模式还是抽象工厂模式,它们本质上都是将不变的部分提取出来,将可变的部分留作接口,以达到最大程度上的复用。究竟用哪种设计模式更适合,这要根据具体的业务需求来决定。