1.什么是工厂模式?
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
2.工厂模式的应用
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:主要解决接口选择的问题。
何时使用:我们明确地计划不同条件下创建不同实例时。
如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码:创建过程在其子类执行。
应用实例:您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
3.实现
factory.cpp
#include <stdio.h>
#include <string>
using namespace std;
//
class product
{
public:
virtual void show() = 0;
};
class productA:public product
{
public:
void show(){
printf("this is productA\n");
}
};
class productB:public product
{
public:
void show(){
printf("this is productB\n");
}
};
class factory
{
public:
product *create(char ch){
int i = 0;
if (ch=='A') i = 1;
if (ch=='B') i = 2;
switch (i) {
case 1 :
return new productA();
break;
case 2 :
return new productB();
break;
default:
break;
}
}
};
int main(){
factory *MyFactory = new factory();
MyFactory->create('A')->show();
MyFactory->create('B')->show();
delete MyFactory ;
return 0;
}
缺点很明显,每当需要增加新的“产品”时,我们不单单要增加一个新的product类,还需要修改工厂类;那么如何解决这个问题呢?想到了宏、模板等思路。
下次继续讨论。
补充:
此程序虽然会正常输出结果:
this is productA
this is productB
但是会造成内存的泄漏,用valgrind工具检查:
valgrind –leak-check=full ./factory
==5721== Memcheck, a memory error detector
==5721== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5721== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5721== Command: ./factory
==5721==
this is productA
this is productB
==5721==
==5721== HEAP SUMMARY:
==5721== in use at exit: 16 bytes in 2 blocks
==5721== total heap usage: 3 allocs, 1 frees, 17 bytes allocated
==5721==
==5721== 8 bytes in 1 blocks are definitely lost in loss record 1 of 2
==5721== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
==5721== by 0x4008AB: factory::create(char) (factory.cpp:36)
==5721== by 0x40078A: main (factory.cpp:49)
==5721==
==5721== 8 bytes in 1 blocks are definitely lost in loss record 2 of 2
==5721== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
==5721== by 0x4008CF: factory::create(char) (factory.cpp:39)
==5721== by 0x4007A6: main (factory.cpp:50)
==5721==
==5721== LEAK SUMMARY:
==5721== definitely lost: 16 bytes in 2 blocks
==5721== indirectly lost: 0 bytes in 0 blocks
==5721== possibly lost: 0 bytes in 0 blocks
==5721== still reachable: 0 bytes in 0 blocks
==5721== suppressed: 0 bytes in 0 blocks
==5721==
==5721== For counts of detected and suppressed errors, rerun with: -v
==5721== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)
我们new了2个product对象却没有释放,导致了内存泄漏。添加析构函数来解决这个问题:
修改后的factory.cpp
class factory
{
public:
product *create(char ch){
int i = 0;
if (ch=='A') i = 1;
if (ch=='B') i = 2;
switch (i) {
case 1 :
pro1 = new productA();
break;
case 2 :
pro1 = new productB();
break;
default:
break;
}
return pro1;
}
~factory(){
delete pro1;
pro1 = NULL;
}
private:
product *pro1;
};
同时必须创建2个指针来新建对象:
main函数部分:
int main(){
factory *MyFactory1 = new factory();
factory *MyFactory2 = new factory();
MyFactory1->create('A')->show();
MyFactory2->create('B')->show();
delete MyFactory1;
MyFactory1 = NULL;
delete MyFactory2;
MyFactory2 = NULL;
return 0;
}
当然,此处不申请堆内存,直接定义指针也可以。
再次检查内存:
==6537== Memcheck, a memory error detector
==6537== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==6537== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==6537== Command: ./factory
==6537==
this is productA
this is productB
==6537==
==6537== HEAP SUMMARY:
==6537== in use at exit: 0 bytes in 0 blocks
==6537== total heap usage: 4 allocs, 4 frees, 32 bytes allocated
==6537==
==6537== All heap blocks were freed -- no leaks are possible
==6537==
==6537== For counts of detected and suppressed errors, rerun with: -v
==6537== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
0内存泄漏,ok!
4.工厂模式扩展——工厂方法模式
所谓工厂方法模式就是在工厂类中把创建产品对象的方法再次封装一次,对外提供接口,同时一个产品对应一个工厂实体类,这样在增加新产品时,不需要改变原代码。新增一个产品类和工厂类即可。遵循了开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改。
代码如下:
#include <stdio.h>
class product
{
public:
virtual void show() = 0;
};
class productA:public product
{
public:
void show() {printf("creat productA ok!\n");}
};
class productB:public product
{
public:
void show() {printf("creat productB ok!\n");}
};
class factory
{
public:
virtual product* creatproduct() = 0;
};
class factoryA:public factory
{
public:
product* creatproduct() {return new productA();}
};
class factoryB:public factory
{
public:
product* creatproduct() {return new productB();}
};
int main(){
factoryA* doworkA = new factoryA();
factoryB *doworkB = new factoryB();
doworkA->creatproduct()->show();
doworkB->creatproduct()->show();
return 0;
}
5.新的工厂模式——抽象工厂
在工厂模式的基础,提出了新的要求:假如产品A出现了新的产品类型,这个时候我们就需要修改工厂A的创建对象的方法,这样很不方便。在抽象工厂类中增加新接口来扩展新的产品的创建方法可以解决这个问题。代码:
#include <stdio.h>
class product
{
public:
virtual void show() = 0;
};
class productA:product
{
public:
void show() {printf("creat productA ok!\n");}
};
class productB:product
{
public:
void show() {printf("creat productB ok!\n");}
};
class multiproduct
{
public:
virtual void show() = 0;
};
class multiproductA:multiproduct
{
public:
void show() {printf("creat multiproductA ok!");}
};
class multiproductB:multiproduct
{
public:
void show() {printf("creat multiproductB ok!");}
};
class factory
{
public:
virtual product* creatproduct() = 0;
virtual multiproduct* creatmulproduct() = 0;
};
class factoryA:factory
{
public:
productA* creatproduct() {return new productA();}
multiproductA* creatmulproduct() {return new multiproductA();}
};
class factoryB:factory
{
public:
productB* creatproduct() {return new productB();}
multiproductB* creatmulproduct() {return new multiproductB();}
};
int main(){
factoryA* doworkA1 = new factoryA();
factoryA* doworkA2 = new factoryA();
factoryB *doworkB1 = new factoryB();
factoryB *doworkB2 = new factoryB();
doworkA1->creatproduct()->show();
doworkA2->creatmulproduct()->show();
doworkB1->creatproduct()->show();
doworkB2->creatmulproduct()->show();
return 0;
}
以上代码编译出现问题:
factoryMethod.cpp:49: error: invalid covariant return type for ‘virtual productA* factoryA::creatproduct()’
factoryMethod.cpp:42: error: overriding ‘virtual product* factory::creatproduct()’
factoryMethod.cpp:50: error: invalid covariant return type for ‘virtual multiproductA* factoryA::creatmulproduct()’
factoryMethod.cpp:43: error: overriding ‘virtual multiproduct* factory::creatmulproduct()’
factoryMethod.cpp:56: error: invalid covariant return type for ‘virtual productB* factoryB::creatproduct()’
factoryMethod.cpp:42: error: overriding ‘virtual product* factory::creatproduct()’
factoryMethod.cpp:57: error: invalid covariant return type for ‘virtual multiproductB* factoryB::creatmulproduct()’
factoryMethod.cpp:43: error: overriding ‘virtual multiproduct* factory::creatmulproduct()’
以上代码有2个问题:一是子类对父类虚函数的实现必须 保证参数、返回类型一致,因此代码片段
product* creatproduct() {return new productA();}
multiproduct* creatmulproduct() {return new multiproductA();}
需改成
product* creatproduct() {return new productA();}
multiproduct* creatmulproduct() {return new multiproductA();}
类似的工厂B也要这样修改。
第二个问题是子类对父类的继承需说明继承类型(pubic、protect、private),如不说明自动按照private的规则继承。这样会导致creatproduct()函数不可见,编译错误。
看来c++基础还没有掌握好,,(⊙﹏⊙)b汗
修改后的代码如下:
#include <stdio.h>
class product
{
public:
virtual void show() = 0;
};
class productA:public product
{
public:
void show() {printf("creat productA ok!\n");}
};
class productB:public product
{
public:
void show() {printf("creat productB ok!\n");}
};
class multiproduct
{
public:
virtual void show() = 0;
};
class multiproductA:public multiproduct
{
public:
void show() {printf("creat multiproductA ok!\n");}
};
class multiproductB:public multiproduct
{
public:
void show() {printf("creat multiproductB ok!\n");}
};
class factory
{
public:
virtual product* creatproduct() = 0;
virtual multiproduct* creatmulproduct() = 0;
};
class factoryA:public factory
{
public:
product* creatproduct() {return new productA();}
multiproduct* creatmulproduct() {return new multiproductA();}
};
class factoryB:public factory
{
public:
product* creatproduct() {return new productB();}
multiproduct* creatmulproduct() {return new multiproductB();}
};
int main(){
factoryA* doworkA1 = new factoryA();
factoryA* doworkA2 = new factoryA();
factoryB *doworkB1 = new factoryB();
factoryB *doworkB2 = new factoryB();
doworkA1->creatproduct()->show();
doworkA2->creatmulproduct()->show();
doworkB1->creatproduct()->show();
doworkB2->creatmulproduct()->show();
return 0;
}
编译通过,执行:
creat productA ok!
creat multiproductA ok!
creat productB ok!
creat multiproductB ok!