Chinaunix首页 | 论坛 | 博客
  • 博客访问: 367478
  • 博文数量: 38
  • 博客积分: 256
  • 博客等级: 入伍新兵
  • 技术积分: 846
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-14 23:21
文章分类

全部博文(38)

文章存档

2015年(1)

2014年(1)

2013年(28)

2012年(8)

我的朋友

分类: C/C++

2012-12-27 01:50:02

创建型设计模式是我们经常需要用到的设计模式之一,顾名思义,这种设计模式是用来创建对象的设计模式。如果你不熟悉,也许会问,我们已经有了构造函数,为什么还需要这种设计模式?为什么我们需要一个中间层专门用来创建对象呢?

我们这里先来设计一个场景,然后来看看为什么我们需要创建型设计模式。

场景:

一般来说,在constructor中,我们有些事情是不可以做的,比如把正在创建的类对象添加到一个global的数据结构中去,比如调用自身的虚函数。如果我们正好遇到这些场景,我们一般会想到利用两段式方法来创建这种对象,在constructor中初步初始化对象成员,然后用另外一个init函数来做进一步的对象初始化,只有在执行完init函数后,这个对象才可以被正确的使用。

那么问题来了,类的用户就必须做两次函数调用才能创建一个对象,这多麻烦,很多用户不愿意这么做,而我们做为设计者,也不应该因为这种原因增加用户的负担。

这样,我们就必须考虑如何解决这个问题。嗯..................

 

解决方案:

1. 想到了没有,你可以提供一个函数把constructor和init包起来,提供一个统一的接口给用户,这样用户就只需要调用一次就可以得到一个可用的对象了。这.......就是传说中的工厂方法(模式)

2. 问题解决了?似乎是。让我们再来看看,如果你要处理的是一组继承体系的类,你也许想为每个实体类定义一个工厂方法,可以的,你可以使用这种方式。但是好吗?客户端必须预先知道他要创建的对象类型,而且没办法更改。这时,我们想到了简单工厂和抽象工厂。它们俩都可以用来解决这个问题,但是它们俩各有优缺点,我不想在这里讨论它们的优缺点。因为你可以在网上找到很多这方面的文章。

那么我想谈点什么呢?谈点我们在做设计时很容易犯的错误,网上大部分讲述工厂模式的例子都有这样的问题。

经典实现:

class animal {

public:

      animal();

      virtual ~animal();

};

class dog: public animal{

public:

     dog();

     ~dog();

};

class cat: public animal {

public:

    cat();

    ~cat();

};

class animalFactory{

public:

      static animal* buildAnimal(...);

};

我不贴实现了,因为这里主要讲设计方面的东西,这些代码已经足够了。

有谁看出这里的问题?...............................没有问题, 你说没有问题?

是的,从编码的角度说,这些代码没有问题,但是从设计的角度来说,这是一个有问题的设计。

既然你提供了一个工厂给类的使用者来创建这些“animal”,而你又把这些animal的构造函数定义在public域,也就是说,即使你提供了animal factory,用户并不是必须通过它才能得到一个animal 对象。如果你到现在还在说没有问题,我就要说你有问题了。

为了代码的可维护性,一般来说,我们只为某一个功能提供一个入口,比如这里的创建功能。你不能让用户既可以使用工厂创建animal对象,也可以使用constructor创建,这样当你想修改你的创建流程是,你所要付出的代价是以提供功能入口数量的指数增长的。

所以一个好的设计,应该是这样:

class animal {

protected:

      animal();

      virtual ~animal();

};

 

class dog: public animal{

friend class animalFactory;

private:

     dog();

     ~dog();

};

 

class cat: public animal {

friend class animalFactory;

private:

    cat();

    ~cat();

};

 

class animalFactory{

public:

      static animal* buildAnimal(...);

};

看到区别了吗?把你不想用户做的事情,明确的用关键字告诉编译器,让它帮你限制用户的行为。

这样,用户只能用你期望的方式来做事情了。因为你屏蔽了其它的途径。所以编译器是是你的朋友,而且是一个非常好的朋友,你必须和他做朋友。

这里讲述的内容适应于所有的创建型设计模式。

阅读(1411) | 评论(0) | 转发(0) |
0

上一篇:线程安全的讨论

下一篇:new/delete 基础

给主人留下些什么吧!~~