一,抽象工厂
目的:抽象工厂主要的作用就是,提供一系列的接口,将对象的创建者和对象的创建过程分离。通俗点将就是将对象new的过程进行封装,通过接口的方式返回对象。
简单的用法:
假设某个用户在建房子,需要钢筋和钢管来搭框架,那么.
用户:client
钢材厂:factory
钢筋:productA
钢管:productB
class productA {
public:
productA();
~productA();
};
class productB {
public:
productB();
~productB();
};
class factory{
public:
virtual productA* createA() { return new productA(); }
virtual productB* createB() { return new productB(); }
};
class client {
protected:
factory* fac;
};
在任何需要产品的时候,用户client只需要通过factory的对象,调用对应的接口,就可以拿到想要产品。
注:这里传送最好使用智能指针,避免导致内存泄漏。
扩展用法:
把抽象工厂和面向对象结合起来。接上面的例子,现在client知道了有两家工厂可以生产钢管和钢筋,但两个工厂生产的产品粗细,质量,价格却不相同,需要在建房时做出选择,那么:
class productA_0 : public productA {
protected:
int len;
int size;
};
class productB_0 : public productB {
protected:
int len;
int size;
};
class productA_1 : public productA {
protected:
int len;
int size;
};
class productB_1 : public productB{
protected:
int len;
int size;
};
class factory_0 : public factory {
public:
virtual productA* createA() { return new productA_0(); }
virtual productB* createB() { return new productB_0(); }
};
class factory_1: public factory {
public:
virtual productA* createA() { return new productA_1(); }
virtual productB* createB() { return new productB_1(); }
};
class client {
public:
client();
~client();
protected:
factory* fac;
};
这样client中定义的代码就不需要改动。只需要在factory创建的时候,根据自己的需要创建对应的工厂对象即可。而且如果需要更换工厂也很方便。
抽象工厂的局限性:
假设用户突然发现,用钢材的成本太高了,现在想要用木材了。那么上面设计的就全部废掉了。
所以抽象工厂在系列产品的扩展/交换方面很有优势。却难以支持新品种的扩展,任何新品种的扩展都需要添加新的工厂。而且对于同一个系列的的产品,一个工厂一次只能使用一种,如果想要同时使用同一个系列的多个产品,则需要创建多个工厂。
二,工厂方法
目的:工厂方法本质上就是一个函数。在一个class中定义一个用于创建对象的接口。与class的继承结合起来,可以让一个类的实例化延迟到子类。
简单的用法:
在user中创建一个create()的func,用于创建Product对象
class Product {
protected:
int param;
};
class user {
public:
virtual Product* create() { return new Product(); }
};
扩展用法:
对于工厂方法的简单用法其实并没有什么意义。我觉得有意思的还是工厂方法与继承的结合。
class Product_0 : public Product{
protected:
int param;
int extend;
};
class Product_1 : public Product {
protected:
int param;
int extend;
};
class user_0 :public user {
public:
virtual Product* create() { return new Product_0(); }
};
class user_1 :public user {
public:
virtual Product* create() { return new Product_1(); }
};
user的子类只需要根据自己的需要,重写create函数即可。这种模式尤其是在写基础代码时有用,很多时候, 并不知道自己定义的class 会被谁用到怎么用。用工厂方法,相当于给子类预留了一个hook,让使用者自己去决定,去生成什么对象。
另外:工厂方法可以携带参数,实现者可以根据传入的参数去决定生产需要的对象。
class user_2:public user {
public:
virtual Product* create( int res ) {
if( res == 0 )
return new Product_0();
else
return new Product_1();
}
};
三,区别
首先,抽象工厂是一个class,而工厂方法只是一个fun。
第二,抽象工厂一般关联多个对象,更注重对象之间的关系,工厂方法只是创建对象。
第三,抽象工厂将对象的创建封装了,如果想要换对象就必须换工厂。而工厂方法,创建对象是可见的。更改对象时,需要直接更改工厂方法。
第四,在某种意义上来说,抽象工厂也可以看作是一个只有工厂方法的class。