设计模式之抽象工厂模式(Abstract Factory)

来源:互联网 发布:天津网络推广招聘 编辑:程序博客网 时间:2024/05/22 11:55

 1.简单实现

        简单工厂模式生活例子 吃饭。 如果你想吃饭了,怎么办自己做吗?自己做就相当于程序中直接使用new。当然是自己下个指令,别人来做更爽。那就把做饭的任务交给你的老婆吧,那么她就是 一个做饭的工厂了,你告诉她要要吃红烧肉,等会她就从厨房给你端出来一盘香喷喷的红烧肉了,再来个清蒸鱼吧,大鱼大肉不能太多,那就再来个爆炒空心菜,最 后再来个西红柿鸡蛋汤。下图 1) 就是这个问题的模型。


       显然到了这里,你是Client,你老婆就是工厂,她拥有做红烧肉的方法,做清蒸鱼的方法,做爆炒空心菜、西红柿鸡蛋汤的方法,这些方法返回值就是食物 抽象。红烧肉、清蒸鱼、爆炒空心菜、西红柿鸡蛋汤就是食物的继承类,到这里你就可以大吃二喝了。简单工厂模式也成型了。哈哈,娶一个手艺不错的老婆还真 好,吃的好,吃的爽,又清闲。 下面来看标准的简单工厂模式的分析。 意图 把一系列拥有共同特征的产品的创建封装 结构图:

代码实现: //---这时一个系列的产品基类class Product{protected:      Product(void){};public:      virtual ~Product(void){};public:     virtual void Function() = 0;};具体产品类:产品1和产品2,这个角色实现了抽象产品角色所定义的接口。代码实现: //产品Aclass ConcreteProductA:public Product{public:     ConcreteProductA(void)     {cout<<"创建 A 产品"<<endl; };public:     virtual ~ConcreteProductA(void)    {cout<<"释放 A 产品"<<endl;}public:     virtual void Function();     {cout<<"这是产品 A 具有的基本功能"<<endl;}};//工厂类:负责具体产品的创建,有两种方式实现产品的创建,I、创建不同的产品用不同的方法;II、创建不同产品用相同的方法,然后通过传递参数实现不同产品的创建。本实例中两种模式都给出了,大家自行分析。 class SimpleFactory{public:      SimpleFactory(){}public:      ~SimpleFactory(){}public:     Product *CreateProduct(int ProuctType)    {           Product *p = 0;           switch(ProductType)           {              case 0:                    p= new ConcreteProductA();                    break;              case 1:                    p= new ConcreteProductB();                    break;              default:                    p= new ConcreteProductA();                    break;            }            return p;      }     Product *CreateProductA()     {return new ConcreteProductA();}     Product *CreateProductB()      {return new ConcreteProductB();}};//客服端程序SimpleFactory sf;Product *p = sf.CreateProductA();p->Function();delete p;p = sf.CreateProductB();p->Function();delete p;

优缺点说明优点:(1) 首先解决了代码中大量New的问题。为何要解决这个问题,好处的说明我想放到结尾总结中。
                            (2) 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。 
缺点:对修改不封闭,新增加产品您要修改工厂。违法了鼎鼎大名的开闭法则(OCP)。

2.深入改进

      人是最贪得无厌的动物,老婆手艺再好,总有不会做的菜,你想吃回锅肉,怎么办,让老婆学呗,于是就给她就新增了做回锅肉的方法,以后你再想吃一个新菜,就 要给你老婆新加一个方法,显然用老婆做菜的缺点也就暴露出来了,用程序设计的描述就是对修改永远不能封闭。当然优点也是有的,你有了老婆这个工厂,这些菜 不用你自己做了,只要直接调用老婆这个工厂的方法就可以了。 
      面对上面对修改不能封闭的问题,有没有好的解决方案吗,如果你有钱,问题就迎刃而解了,把老婆抽象变成一个基类,你多娶几个具体的老婆,分别有做鱼 的,做青菜的,炖汤的老婆,如果你想吃一个新菜,就再新找个女人,从你的老婆基类继承一下,让她来做这个新菜。显然多多的老婆这是所有男人的梦想,没有办 法,法律不允许,那么咱们只是为了做饭,老婆这个抽象类咱们不叫老婆了,叫做厨师吧,她的子类也自然而然的该叫做鱼的厨师、炖汤的厨师了。现在来看这个模 式发生了变化,结构中多了一个厨师的抽象,抽象并不具体的加工产品了,至于是炖汤还是炖鱼,是由这个抽象工厂的继承子类来实现,现在的模式也就变成工厂方 法模式了,这个上面的结构图1)就变成了下面的图3的结构了。


      现在再来分析现在的模式,显然简单工厂的缺陷解决了,新增加一个菜只需要新增加一个厨师就行了,原来的厨师还在做原来的工作,这样你的设计就对修改封 闭了。你看把老婆解放出来,招聘大量的厨师到你家里这个方案多么的完美,你老婆也会爱死你了。当然前提就是你要有多多的钱噢,当然这里的钱的多少在软件领 域应该看你的客户软件投资方的要求。 
     下面来一下标准的工厂模式的实现意图。
定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。上面是GOF关于此模式的意图描述,我想补充的是您可以这样理解:为了改善简单工厂对修改不能关闭的问题。
结构


//工厂模式,此模式的工厂只定义加工产品的接口,具体生成交予其继承类实现//只有具体的继承类才确定要加工何种产品class Factory{public:       Factory(void){};public:      virtual ~Factory(void){};public:      virtual Product* CreateProduct(int ProductType = 0) =0;};//具体工厂类:工厂基类的具体实现,由此类决定创建具体产品,这里 ConcreteFactory1 对于与图中的 工厂实现,ConcreteFactory2 对于与图中的新工厂。class ConcreteFactory1:public Factory{public:      ConcreteFactory1(){};public:      virtual ~ConcreteFactory1(){};public :      Product* CreateProduct(int ProductType)      {             Product *p = 0;             switch(ProductType)             {                   case 0:                        p= new ConcreteProductA();                        break;                  case 1:                        p= new ConcreteProductB();                        break;                 default:                        p= new ConcreteProductA();                        break;             }            return p;       }};class ConcreteFactory2:public Factory{public:      ConcreteFactory2(){};public:      virtual ~ConcreteFactory2(){};public :      Product* CreateProduct(int ProductType)      {return new ConcreteProductANew();}};//客户调用Factory*fct = new ConcreteFactory1();Product *p = fct->CreateProduct(0);p->Function();delete p;p = fct->CreateProduct(1);p->Function();delete p;delete fct;fct = new ConcreteFactory2();p=fct->CreateProduct();delete p;delete fct;

缺点:对于创建不同系列的产品无能为力 适用性

  •            当一个类不知道它所必须创建的对象的类的时候。
  •            当一个类希望由它的子类来指定它所创建的对象的时候。
  •            当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

3.继续深入改进

        抽象工厂模式生活例子     世事多变,随着时间的推移,走过的地方越来越多,你天南海北的朋友也越来越多。你发现菜原来还分了许多菜系,鲁菜、粤菜、湘菜等等,它们各有各的风味,同 样是红烧肉由不同菜系出来的味道也各不相同, 你招待不同的朋友要用不同的菜系,这下难办了,你的厨师都是鲁菜风味,怎么办,广东的朋友来了吃不惯。现在我们再回到简单工厂模式(就是老婆做菜的模 式),我们把红烧肉再向下继承,生成鲁菜红烧肉、粤菜红烧肉、湘菜红烧肉;清蒸鱼向下继承为鲁菜清蒸鱼、粤菜清蒸鱼、湘菜清蒸鱼,其它也以此类推。我们也 修改一下老婆的这个类,不让其返回食物基类,而是返回红烧肉、清蒸鱼、爆炒空心菜、西红柿鸡蛋汤这一层次,并把这些方法抽象化,作为菜系工厂基类,然后再 从此基类继承出,鲁菜工厂、粤菜工厂、湘菜工厂等等,再由这些具体工厂实现创建具体菜的工作,哈哈你如果招待广东朋友就用粤菜工厂,返回的就是一桌粤菜菜 系的红烧肉、清蒸鱼、空心菜和西红柿鸡蛋汤了,你的广东朋友一定会吃的非常合乎胃口了。噢,非常好,你已经实现了抽象工厂模式了。


 现在可以看到,想新来做一个菜系,只需新聘请一个厨师就可以了,多么完美,但是你先别高兴太早,如果你想新增加一个菜就变得非常困难了。
意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 



//产品Aclass ConcreteProductA:public Product{public:      ConcreteProductA(void)         {cout<<"创建 A 产品"<<endl;}public:     virtual ~ConcreteProductA(void)     {cout<<"释放 A 产品"<<endl;}public:     virtual void Function()     {cout<<"这是产品 A 具有的基本功能"<<endl;}};//产品B与A类似不这里不再给出//下面是具体的产品class ConcreteProductA1:public ConcreteProductA{public:ConcreteProductA1(void){cout<<"创建 A1 产品"<<endl;}public:virtual ~ConcreteProductA1(void){cout<<"释放 A1 产品"<<endl;}public:virtual void Function(){cout<<"这时产品 A1 具有的基本功能"<<endl;}};//抽象工厂class AbstractFactory{public:AbstractFactory(){};public:virtual ~AbstractFactory(){};public:virtual ConcreteProductA* CreateA() = 0;virtual ConcreteProductB* CreateB() = 0;};//具体工厂实现类:工厂1和工厂2。新增加系列,只需新实现一个工厂。class ConcreteAbsFactory1:public AbstractFactory{public:ConcreteAbsFactory1(){};public:virtual ~ConcreteAbsFactory1(){};public:virtual ConcreteProductA* CreateA() {return new ConcreteProductA1();}virtual ConcreteProductB* CreateB(){return new ConcreteProductB1();}};//客户访问代码AbstractFactory *absfct = new ConcreteAbsFactory1();ConcreteProductA *cpa = absfct->CreateA();cpa->Function();delete cpa;ConcreteProductB *cpb = absfct->CreateB();cpb->Function();delete cpb;delete absfct;absfct = new ConcreteAbsFactory2();cpa = absfct->CreateA();cpa->Function();delete cpa;cpb = absfct->CreateB();cpb->Function();delete cpb;


原创粉丝点击