C++必知必会之(30)Factory Method模式

来源:互联网 发布:淘宝违规记录怎么清除 编辑:程序博客网 时间:2024/06/07 17:51

1、一个高级设计通常要求基于一个现有对象类型来创建一个“适当”类型的对象。

例如:我们可能拥有一个指向某种类型的Employee对象的指针或引用,现在需要为该类型的Employee生成一个适当类型的HRInfo对象。

高级设计方案简单:“为这个雇员创建一个适当类型的记录”。很多人却将此类需求当成执行运行期类型查询的接口。换句话说,为了决定待产生的HRInfo对象的类型,实现此项需求的代码仅仅是询问一系列关于Employee的确切类型问题。

一个常见到的错误是使用“类型编码”和switch结构:

class Emplyee  {

     public:

         enum Type  {   SALARY, HOURLY, TEMP  };

         Type  type( )  const  {  return type_;   }

          //.....

     private:

         Type type_;

          //.....

};

//....

HRInfo  *genInfo( const Employee  &e )  {

     switch( e.type( ) )   {

        case SALARY:

        case HOURLY: return new StdInfo( e);

        case TEMP::return new TempInfo( static_cast< const Temp *p> (e) );

        default:   return 0;           //未知的类型代码!

        }

}

另外一种糟糕方式,使用dynamic_cast来询问关于Employee对象一系列的私人问题:

HRInfo  *genInfo ( const Employee  &e)  {

      if( const Salary *s = dynamic_cast<const Salary  *> ( &e) )

           return new StdInfo( s);

       else if( const Hourly *h = dynamic_cast<const Hourly *>( &e) )

              return new StdInfo( h);

       else if( const Temp *h = dynamic_cast<const Temp *>( &e) )

              return new TempInfo( t);

        else

            return 0;       //未知的employee类型!

}

这两种genInfo实现的缺点在于,它们与所有从Employee和HRInfo派生下来的具体类型相耦合,并且它们还必须熟悉从每一种Employee类型到其相对应的HRInfo类型的映射。

任一Employee、HRInfo或二者之间的映射发生了改动,都需要你去维护代码。

另一个问题是,这两种方式都可能无法成功地识别Employee实参的确切类型,从而要求调用genInfo的代码提供对错误情况的处理。


正确的方式是考虑从每一种Employee类型到对应的HRInfo类型的映射应该置于何处。

换句话说,谁最清楚一个Temp employee需要何种HRInfo对象?理所当然,是Temp employee自己:

class Temp : public Employee {

   public:

        //...

    TempInfo  *genInfo( ) const

           {  return new TempInfo ( *this);  }

       //.....

};

这时,我们可能还不知道我们是在处理一个Temp employee而不是别的类型的employee。

解决方法只要提供一个(纯)虚函数就可以了:

class Employee  {

       public:

             //...

             virtual HRInfo  *genInfo( )  const = 0;      //Factory Method

            //....

};

这是一个Factory Method模式的实例。

实际上,我们不是想employee询问一系列的私人问题,而是说“不管您是什么类型的employee,请为自己生成适当的HRInfo对象”:

Employee *e = getAnEmployee( );

//....

HRInfo  *info = e->genInfo( );         //使用Factory Method

Factory Method的本质在于,基类提供一个虚函数“挂钩”,用于产生适当的“产品”。

每一个派生类可以重写继承的虚函数,为自己产生适当的产品。

实际上,我们具备了使用一个未知类型的对象(例如某种Employee对象)来产生另一个未知类型的对象(例如适当的HRInfo对象)的能力。


使用Factory Method模式通常意味着一个高级设计需要基于一个对象的准确类型产生另一个“适当”的对象,这样的需要往往发生于存在多个平行或几乎平行的类层次结构的情况下。

Factory Method模式通常是治疗一系列运行期类型查询问题的良方。

       

0 0
原创粉丝点击