Symbian常用设计模式之可伸缩对象工厂

来源:互联网 发布:gif图查看软件 编辑:程序博客网 时间:2024/05/17 12:20

 

1.对象型别依存性

例如:
类结构
class Animal{};
class Cat : public Animal{};
class Dog : public Animal{};
实例猫的对象
Animal* pb = new Cat(); 
这里出现了具体型别Cat。如果我们要构造狗的实例,就需要编码时将这句话中的Cat改成Dog。也就是编译期必须完全确知对象的类型。
虚特性的特点是执行期才确定对象类型,那么显然new操作符并不具备虚函数的特点。
能否在执行期时识别对象型别,生成对象呢?

2.执行期识别--虚构造函数

按照上述构想,执行期时获得对象类型Cat,传给Animal对象的统一的创建方法,创建正确的对象并把指向基类的指针返回。这分明就是把构造方法改造成虚函数。可惜C++中没有虚构造函数。new操作符也不支持虚特性。
变通的方法是在工厂中提供CreateAnimal的方法,把Animal的类别传进去,用switch/case识别,然后构造正确的实例
Animal* AnimalFactory::CreateAnimal( int animalType )
{
   switch ( animalType )
   {
       case Cat:
              return new Cat();
       case Dog:
              return new Dog();
   }
   return null;
}
这样实现了执行期动态识别对象型别。
问题是它执行了switch,有了switch语句的最大缺点,不利于程序扩展。当增加一个类Bird时,需要到AnimalFactory.cpp中增加一种对象类型,还要到switch中增加一个case,还要到增加一个#include "bird.h"。增加一个Bird类,却要在AnimalFactory类中作这么多改变,增加了类之间的耦合性,显然这不是一个好的设计。

3.可伸缩工厂

当你增加一种产品时,不必修改工厂的代码,这就是可伸缩工厂,这就是我们想得到的。
实现方法是在将创建产品方法中的switch识别改为函数指针识别,同时维护一张对象型别到函数指针的映射表。如:
Cat->Animal* CreateCat()
Dog->Animal* CreateDog()
Bird->Animal* Bird()
类型Cat和CreateCat方法在cat.cpp中提供,并把Cat到CreateCat的映射注册到Factory中的映射表中。
依次类推,如果增加Bird类,只要在Bird.cpp中增加Bird的类型ID和CreateBird方法,并调用Factory的Regist方法,把这个映射注册到Factory中即可,不涉及一点Factory的代码的修改。
可以用std:map作这个映射表。
修改后的Factory如下
class AnimalFactory
{
public:
        typedef Animal* (*CreateAnimalCallback)();
        typedef std::map< int, CreateAnimalCallback > AnimalMap;
        Animal* CreateAnimal( int animalType );
        bool RegistAnimal( int animalType, CreateAnimalCallback callback );
private:
        AnimalMap map_;
}
Animal* AnimalFactory::CreateAnimal( int animalType )
{
     AnimalMap::const_iterator i = map_.find( animalType );
     if ( i == map_.end() )
     {
         throw std::runtime_error("Unknown Shape ID");
     }
     return ( i->sencond)();
}
bool AnimalFactory::RegistAnimal( int animalType, CreateAnimalCallback callback )
{
     return map_.insert( AnimalMap::value_type( animalType, callback ) ).second;
}
在cat.h中
const int Cat = 1; //定义全局变量,猫的型别标示
Animal* CreateAnimal(); //定义全局函数,用于生成猫的对象。
class Cat : public Animal{}; //定义猫的类。

4.Symbian中实现可伸缩的对象工厂

Symbian中不能用std::map这个数据类型,所以需要自己实现map表。

我写了一个类TMapModel,里面有两个成员变量,一个TUid,一个指向函数的指针,从而完成一对映射。

在Factory类中,用RArray<TMapModel>,将所有映射关系组合起来,作为Map表。

具体实现如下

(1) mapmodel.h //映射关系头文件

#ifndef T_MAPMODEL_H
#define T_MAPMODEL_H
 
#include <e32base.h>
 
class CAknView;

class TMapModel
    {
public:
    typedef CAknView* (*CreateViewCallback)();
   
    TMapModel( TUid aViewId, CreateViewCallback aCreateCallback );
   
    inline TUid ViewId()
        {
        return iViewId;
        };
   
    inline CreateViewCallback CreateCallback()
        {
        return iCreateCallback;
        };
private:
    TUid iViewId;   
    CreateViewCallback iCreateCallback;
    };
   
#endif

(2) mapmodel.cpp

#include "mapmodel.h"

TMapModel::TMapModel( TUid aViewId, CreateViewCallback aCreateCallback )
          :iViewId( aViewId ), iCreateCallback( aCreateCallback )
    {
    }

(3) viewfactory.h // 工厂类头文件

#ifndef C_VIEWFACTORY_H
#define C_VIEWFACTORY_H
 
#include <e32base.h>

#include "mapmodel.h"
 
class CViewFactory : public CBase
    {
public:       
    static CViewFactory* NewL();
    static CViewFactory* NewLC();
    ~CViewFactory();
   
    TInt RegistViewL( TUid aViewId, TMapModel::CreateViewCallback aCreateCallback );
    CAknView* CreateViewL( TUid aViewId );

private:
    void ConstructL();
   
private:
    RArray<TMapModel> iMap;
    };
   
#endif //C_VIEWFACTORY_H

(4) viewfactory.cpp //工厂类的实现


#include <aknview.h>
#include "mapmodel.h"
#include "viewfactory.h"

CViewFactory* CViewFactory::NewL()
    {
    CViewFactory* self = CViewFactory::NewLC();
    CleanupStack::Pop();
    return self;
    }
   
CViewFactory* CViewFactory::NewLC()
    {
    CViewFactory* self = new (ELeave) CViewFactory();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }
   
CViewFactory::~CViewFactory()
    {
    iMap.Close();
    }
   
void CViewFactory::ConstructL()
    {
    }
   
TBool CViewFactory::RegistViewL( TUid aViewId, TMapModel::CreateViewCallback aCreateCallback )
    {   
    iMap.AppendL( TMapModel( aViewId, aCreateCallback ) );
    return ETrue;
    }

CAknView* CViewFactory::CreateViewL( TUid aViewId )
    {
    CAknView* view = NULL;
    TInt i = 0;
    for ( i = 0; i < iMap.Count(); i++ )
        {
        if ( iMap[i].ViewId() == aViewId )
            {
            TMapModel::CreateViewCallback callback =
            iMap[i].CreateCallback();
            return callback();           
            }
        }
    if ( i == iMap.Count() )
        {
        User::Leave( KErrNotFound );
        }
    return view;       
    }

(5) 使用方法

在appui类的构造方法中实例化factory类,然后进行类的注册。

void CMyAppUi::ConstructL()
    {
    BaseConstructL( EAknEnableSkin );   
   
    iViewFactory = CViewFactory::NewL();
   
    // Regist view
    iViewFactory->RegistViewL( KCatViewId, CreateCatViewL );    
    iViewFactory->RegistViewL( KDogViewId, CreateDogViewL );

  
    // Create view
    CAknView* view = iViewFactory->CreateViewL( KCatId );

    CleanupStack::PushL( view );

    AddViewL( view );

    SetDefaultViewL( *view );

    CleanupStack::Pop();
    }

原创粉丝点击