• [设计模式3]--工厂(Factory)模式


    原文出处:http://blog.csdn.net/lwbeyond/article/details/7528309

    工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。

    一. 简单工厂模式

    简单工厂模式,它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。举个例子,有一家电子产品生产厂家,它只有一个工厂,能够生产两种型号的产品,A 和 B。可以想像一下,A是电吹风,B是电风扇。客户需要什么样的吹风类产品,一定要显示地告诉生产工厂。

    代码实现:

    [cpp] view plaincopy
     
    1. enum CTYPE {PRODUCT_A, PRODUCT_B};  
    2.   
    3. //抽象产品类  
    4. class Product      
    5. {  
    6. public:      
    7.     virtual void Show() = 0;    
    8. };      
    9.   
    10. //具体产品A      
    11. class ProductA: public Product      
    12. {  
    13. public:      
    14.     void Show() { cout<<"Product A"<<endl; }      
    15. };      
    16.   
    17. //具体产品B      
    18. class ProductB: public Product      
    19. {      
    20. public:      
    21.     void Show() { cout<<"Product B"<<endl; }      
    22. };      
    23.   
    24. //唯一的工厂,可以生产两种型号的产品,在内部判断  
    25. class Factory      
    26. {  
    27. public:       
    28.     Product* CreateProduct(enum CTYPE ctype)      
    29.     {      
    30.         if(ctype == PRODUCT_A) //工厂内部判断      
    31.             return new ProductA(); //生产产品A      
    32.         else if(ctype == PRODUCT_A)      
    33.             return new ProductB(); //生产产品B      
    34.         else  
    35.             return NULL;  
    36.     }  
    37. };  
    38.   
    39.   
    40. int main()  
    41. {  
    42.     Factory fac; //工厂  
    43.   
    44.     Product *pro = fac.CreateProduct(PRODUCT_A);//生产产品A  
    45.   
    46.     pro->Show();  
    47.   
    48.     return 0;  
    49. }  

    缺点:

    由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

    打个比方:

    这个工厂在刚建厂时,就要事先把以后的要生产的产品考虑好,部门划分好。如果要生产新的产品,就要改变工厂的空间布局,部门也要重新划分,这是很不利的。当然如果工厂以后发展不大,也就是创建的对象比较少时,还是可以用的。

    二. 工厂方法模式

    所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

    还以刚才的例子解释,这家电子厂赚了不少钱,于是决定再开设一个厂,其中一个工厂专门用来生产A型号的产品,也就是只生产电吹风,而另一工厂专门用来生产B型号的产品,也就是只生产电风扇,这样分工明确了。以后客户要再下定单时,可以直接找到相关的工厂了,比如要A型号的产品,就找A工厂要,不再担心下的定单是A,生产出来的是B产品了。

    代码实现:

    [cpp] view plaincopy
     
    1. class Product    
    2. {    
    3. public:    
    4.     virtual void Show() = 0;  
    5. };    
    6.   
    7. //产品A  
    8. class ProductA: public Product    
    9. {    
    10. public:    
    11.     void Show()  
    12.     {  
    13.         cout<<"Product A"<<endl;  
    14.     }  
    15. };  
    16.   
    17. //产品B    
    18. class ProductB: public Product    
    19. {    
    20. public:    
    21.     void Show()  
    22.     {  
    23.         cout<<"Product B"<<endl;  
    24.     }  
    25. };    
    26.   
    27. //抽象工厂  
    28. class Factory  
    29. {    
    30. public:    
    31.     virtual Product* CreateProduct() = 0;  
    32. };  
    33.   
    34. //生产A的工厂    
    35. class FactoryA: public Factory    
    36. {  
    37. public:  
    38.     Product* CreateProduct()  
    39.     {  
    40.         return new ProductA;  
    41.     }  
    42. };    
    43.   
    44. //生产B的工厂    
    45. class FactoryB: public Factory    
    46. {    
    47. public:  
    48.     Product* CreateProduct()  
    49.     {  
    50.         return new ProductB;  
    51.     }  
    52. };  
    53.   
    54. int main()  
    55. {  
    56.     Factory* fac = new FactoryA(); //A工厂  
    57.   
    58.     Product* p = fac->CreateProduct(); //生产产品  
    59.   
    60.     p->Show();  
    61.   
    62.     return 0;  
    63. }  

    其实你会发现,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行,你想要加功能,本来是改工厂类的,而现在是修改客户端。

    这有什么好处呢?举个例子,有三个客户原来要A产品,现在改卖B产品,在代码中体现为:

    简单工厂的处理:

    [cpp] view plaincopy
     
    1. Factory fac; //工厂  
    2.   
    3. Product *pro1 = fac.CreateProduct(PRODUCT_A);//生产产品A  
    4. Product *pro2 = fac.CreateProduct(PRODUCT_A);//生产产品A  
    5. Product *pro3 = fac.CreateProduct(PRODUCT_A);//生产产品A  
    6.   
    7. //改为B产品,这里要改三个地方  
    8. //Product *pro1 = fac.CreateProduct(PRODUCT_B);//生产产品B  
    9. //Product *pro2 = fac.CreateProduct(PRODUCT_B);//生产产品B  
    10. //Product *pro3 = fac.CreateProduct(PRODUCT_B);//生产产品B  
    11.   
    12. pro1->Show();  
    13. pro2->Show();  
    14. pro3->Show();  

    工厂方法的处理:

    [cpp] view plaincopy
     
    1. Factory* fac = new FactoryA(); //A工厂  
    2.   
    3. //改为B产品,这里只改一个地方  
    4. //Factory* fac = new FactoryB(); //B工厂  
    5.   
    6. Product* pro1 = factory_A->CreateProduct(); //生产产品  
    7. Product* pro2 = factory_A->CreateProduct(); //生产产品  
    8. Product* pro3 = factory_A->CreateProduct(); //生产产品  
    9.   
    10. pro1->Show();  
    11. pro2->Show();  
    12. pro3->Show();  

    这里可以看到工厂方法的好处了吧,工厂方法模式是简单工厂模式的进一步抽象和推广,它集中封装了对象的创建,使得要更换产品时,不需要做大的改动就可以实现,降低了客户程序与产品对象的耦合。

    优点:

    相对于简单工厂模式来说,这样分工更加明确,当需要新产品时,就建一个新的工厂,而不是对原工厂类进行修改。这样做满足了"开放-封闭"原则,即可以扩展,不可修改。

    缺点:

    1. 每增加一种产品,就需要增加一个对象的工厂。在C++实现中,就是要定义一个个的工厂类。显然,相比简单工厂模式,工厂方法模式需要更多的类定义。

    2. Factory 模式仅仅局限于一类类(就是说 Product 是一类,有一个共同的基类),如果我们要为不同类的类提供一个对象创建的接口,那就要用AbstractFactory了。

    打个比方:

    如果这家公司发展迅速,推出了很多新的产品,那么就要开设相应的新工厂,一种产品一个工厂。这对于客户来说是好事,分工明确了白;但对于工厂自己来说开销也变大了。

    如要我想要生产核心芯片,但是芯片不是产品,不能继承于product类。因为产品和零部件,不是一类。

    三. 抽象工厂模式

    抽象工厂模式,它定义为提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

    还以上面的例子解释,这家公司经营的还不错,针对其核心技术都申请了专利,后来生始生产相关电子芯片了 (像三星一样,即生产产品也生产芯片)。对于这种情况,我们不能在抽象产品类上继承一个零部件,因为产品和芯片没有什么共同之处,完全是两个领域。你要做芯片,就要专心做,当成一个新的领域,不能用以前产品的那一套流程。这样划分才明确,才能更好的实现高内聚,低耦合的明标。

    [cpp] view plaincopy
     
    1. //抽象产品类  
    2. class Product  
    3. {    
    4. public:    
    5.     virtual void Show() = 0;  
    6. };  
    7.   
    8. //产品A  
    9. class ProductA: public Product    
    10. {    
    11. public:  
    12.     void Show()  
    13.     {  
    14.         cout<<"Product A"<<endl;  
    15.     }  
    16. };  
    17.   
    18. //产品B    
    19. class ProductB: public Product    
    20. {    
    21. public:    
    22.     void Show()  
    23.     {  
    24.         cout<<"Product B"<<endl;  
    25.     }  
    26. };    
    27.   
    28. //抽象芯片类  
    29. class Chip  
    30. {  
    31. public:    
    32.     virtual void Show() = 0;  
    33. };  
    34.   
    35. //芯片A  
    36. class ChipA: public Chip    
    37. {    
    38. public:    
    39.     void Show()  
    40.     {  
    41.         cout<<"Chip A"<<endl;  
    42.     }  
    43. };  
    44.   
    45. //芯片B    
    46. class ChipB: public Chip    
    47. {    
    48. public:    
    49.     void Show()  
    50.     {  
    51.         cout<<"Chip B"<<endl;  
    52.     }  
    53. };  
    54.   
    55.   
    56. //抽象工厂类  
    57. class Factory  
    58. {    
    59. public:    
    60.   virtual Product* CreateProduct() = 0;  
    61.   virtual Chip* CreateChip() = 0;  
    62. };  
    63.   
    64. //生产A的工厂  
    65. class FactoryA: public Factory    
    66. {  
    67. public:  
    68.     Product* CreateProduct() //产品  
    69.     {  
    70.         return new ProductA;  
    71.     }  
    72.   
    73.     Chip* CreateChip() //芯片  
    74.     {  
    75.         return new ChipA;  
    76.     }  
    77. };    
    78.   
    79. //生产B的工厂  
    80. class FactoryB: public Factory  
    81. {    
    82. public:  
    83.     Product* CreateProduct() //产品  
    84.     {  
    85.         return new ProductB;  
    86.     }  
    87.   
    88.     Chip* CreateChip()  //芯片  
    89.     {  
    90.         return new ChipB;  
    91.     }  
    92. };  
    93.   
    94.   
    95. int main()  
    96. {  
    97.     Factory* factury = new FactoryA(); //A工厂  
    98.       
    99.     Product* product = factury->CreateProduct(); //生产产品  
    100.     Chip* chip = factury->CreateChip(); //生产芯片  
    101.   
    102.     product->Show();  
    103.     chip->Show();  
    104.   
    105.     return 0;  
    106. }  

    我们可以发现,抽象工厂比工厂模式所能处理的产品更多,最关健的是这些产品有不同的基类。

    优点:

    1. AbstractFactory 模式关键就是将这一组对象的创建封装到一个用于创建对象的工厂类(ConcreteFactory)中,维护这样一个工厂创建类总比维护 n 多相关对象的创建过程要简单的多。

    2. 它的最大好处是易于交换产品系列,比如我要B工厂的产品,只需要在客户端代码修改一处即可。

    打个比方:

    这时客户只要知道A工厂是生产A类的产品和芯片的,B工厂是生产B类的,其它都不用关心,只要想要与A类相关的东东就去找A就行了。

    四. 总结:

    1. 简单工厂模式,所有的产品都在工厂类中进行生产。功能单一时,没有什么问题,但是当增加很多新产品时,就要不断的修改产品类,易于出错,也违反了对修改是封闭的原则。

    2. 工厂方法模式,每个工厂生产一种产品,这样分工更加明确。当增加新产品时,只需增加一个工厂类,而不用修改原有工厂类,这样工厂类的耦合度就降低了。

    3. 抽象工厂模式,比工厂方法模式处理的情况更多。主要是对不同产品的处理,这时的工厂能够生产多种产品,这多种产品虽然没有共同基类,但是却属于一类,具体体现在都是由同一个工厂生产。

  • 相关阅读:
    JVM堆内存设置和测试
    转:面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”
    JVM--标记-清除算法Mark-Sweep
    JVM 垃圾回收器工作原理及使用实例介绍
    BSGS算法(大小步算法)
    Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)
    Codeforces Round #605 (Div. 3)
    POJ 2516Minimum Cost(最小费用流+特判)
    POJ 3155Hard Life(最大密度子图)
    洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)
  • 原文地址:https://www.cnblogs.com/hustcser/p/4362151.html
Copyright © 2020-2023  润新知