0%

设计模式初探-VISSIM中简单工厂模式

前言

其实自己的写的是一个非常小的程序,不过根据《大话设计模式》的书中来说,再小的程序也可以体现出设计模式。
虽然很早之前就看了设计模式的相关技巧,可能是自己的语言功底不够,在实现上面总是懵懵懂懂,好像知道大体的概念,具体的实现却常常浅尝辄止。这次在完成VISSIM-ORACLE的仿真平台过程中,一个被放在第一节的简单工厂模式就让自己吃了不少苦头,因此,需要进行一定的总结。
在完成这篇日志时,C++属于初学阶段,代码有问题或者可优化的地方请大家指出,多谢。

问题描述

VISSIM提供了COM接口,提供了很多与VISSIM中对应的类型,在使用这些类型的时候,由于大多数学习交通的同学对语言并不熟悉或者对设计模式并不熟悉,导致在调用VISSIM对象时候,在主函数会出现下面的代码:

1
2
3
4
5
6
//C++ code
//COM调用过程省略
IVissimPtr VissimPrt ;
IVehicleInputPtr VI1 = VissimPrt ->GetNet()->GetVehicleInputs()->GetVehicleInputByNumber(1);
IVehicleInputPtr VI2 = VissimPrt ->GetNet()->GetVehicleInputs()->GetVehicleInputByNumber(2);
//...其他类似

每次在使用的时候都新建一个实例个人觉得是非常落后和笨的方法,少量的对象引用可以采用,但是大量的不同类型的对象会出现后面代码十分难维护的问题。而且每个新建的对象的性能开销在那,会影响性能(学习C++之后才开始重视性能方面)。

基本实现过程

简单工厂模式是设计模式里面比较初级的模式了,基本就是用到了简单的继承和多态知识。主要的作用在于按照自己的需求来返回相应的类型对象。

抽象基类和子类

在实现简单工厂模式需要为工厂建立一个基类,基类应该包含所有类型的基本信息。
在调用VISSIM的过程中,我们主要的目标基本是从对应的VISSIM对象中读取数据和向对应的VISSIM对象中写入数据,因此可以抽象出base类,然后在派生出几个VISSIM对象类,这里只举个简单例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//VisObjBase.h
//vissim对象的基类
class VissimObjectBase
{
protected:
VissimBase* vissimbase_;//这是自己建立的vissim类,与c++调用vissim无关
long id_;
_bstr_t keyword_;
public:
VissimObjectBase(VissimBase*,long,char*);
~VissimObjectBase();
virtual double GetValue();
};
//车辆输入类,公有继承
class VissimVehInp:public VissimObjectBase
{
public:
VissimVehInp(VissimBase* VB,long id,char* kw):VissimObjectBase(VB,id,kw){};
double GetValue() override;
};
//检测器类
class VissimDataColl:public VissimObjectBase
{
public:
VissimDataColl(VissimBase* VB,long id,char* kw):VissimObjectBase(VB,id,kw){};
double GetValue() override;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
////VisObjBase.cpp
VissimObjectBase::VissimObjectBase(VissimBase* vissimbase,long id,char* keyword)
{
this->vissimbase_ = vissimbase;
this->id_ = id;
this->keyword_ = _com_util::ConvertStringToBSTR(keyword);
}

double VissimObjectBase::GetValue()
{
return 0;
}

//各类获取参数实现
double VissimVehInp::GetValue()
{
try
{
VARIANT var = vissimbase_->GetVissim()->GetNet()->GetVehicleInputs()->GetVehicleInputByNumber(id_)->GetAttValue(_bstr_t(keyword_));
return var.dblVal;
}
catch(_com_error e)
{
cout<<e.ErrorMessage()<<endl;
return 0;
}

}

double VissimDataColl::GetValue()
{
try
{
VARIANT var = vissimbase_->GetVissim()->GetNet()->GetDataCollections()->GetDataCollectionByNumber(id_)->GetAttValue(_bstr_t(keyword_));
return var.dblVal;
}
catch(_com_error e)
{
cout<<e.ErrorMessage()<<endl;
return 0;
}
}

在创建类型中的几个tips:

  • 抽象出所有类都需要的方法,并用虚函数表示,在其他子类中进行override
  • 基类中的对象的属性设置注意,private在子类中无法访问
  • 子类采用公有继承的方式

工厂类实现

在实现工厂过程中,需要用一个“代号”去表征创建的类是什么,这里基于两个方面(对C++字符串理解不深入,以及尝试map容器)采用map方式实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//VisObjFac.h
#include <map>
#include <iostream>
#include <string>
using namespace std;

class VissimObjectFactory
{
private:
typedef map<string,int> MatchMap;
MatchMap MatchMap_;
public:
VissimObjectFactory();
~VissimObjectFactory();
VissimObjectBase* GetVissimObjcet(VissimBase* ,string,long,char*);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//VisObjFac.cpp
#include "VisObjFac.h"
#include <iostream>
//工厂类构造函数
VissimObjectFactory::VissimObjectFactory()
{
MatchMap_["VehInp"]=1;
MatchMap_["DataColl"]=2;
}
//析构函数
VissimObjectFactory::~VissimObjectFactory(){}
//工厂函数
VissimObjectBase* VissimObjectFactory::GetVissimObjcet(VissimBase* vissimBase,string Type,long ID,char* keyword)
{
try
{
int typenum = MatchMap_[Type];
if (typenum == 1) return new VissimVehInp(vissimBase,ID,keyword);
else if (typenum == 2) return new VissimDataColl(vissimBase,ID,keyword);
else return 0;
}
catch(_com_error e)
{
std::cout<<e.ErrorMessage()<<std::endl;
return 0;
}
}

至此,简单的工厂类就完成了,新建对象只需要用对应的字符串”VehInp”,”DataColl”生成。

主函数调用

1
2
3
4
5
6
//其他程序略
//main.cpp
VissimObjectFactory* objectbase = new VissimObjectFactory();
VissimObjectBase* testinput = objectbase->GetVissimObjcet(vissimBase,"VehInp",1,"VOLUME");//即可返回id为1的车辆输入对象
testinput = objectbase->GetVissimObjcet(vissimBase,"VehInp",2,"VOLUME");//即可返回id为2的车辆输入对象
cout<< testinput->GetValue()<<endl;