apollo 7.0——工厂设计模式解析
工厂模式
工厂方法是一种创建型设计模式,与简单工厂(Simple Factory)、抽象工厂(Abstract Factory)一并称为工厂模式,关于三者的区别可以概括为:
- 简单工厂:只有一个工厂,将不同产品的生产语句罗列到工厂的一个生产方法中,根据配置参数选择性生产具体的产品;
- 工厂方法:也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象了。
- 抽象工厂:将不同的产品根据相关性划分为多个产品族,每个产品族对应一个具体工厂,每个具体工厂中包含多个产品生产方法,用于生产对应产品族中的不同产品。
应用:工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
-
在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式;
-
产品结构较复杂的情况下,可以使用工厂方法模式;
apollo实例解析
下面结合apollo源码实例进行分析:
打开apollo/modules/perception/lidar/lib/interface/base_lidar_obstacle_detection.h
看下 BaseLidarObstacleDetection类的定义
class BaseLidarObstacleDetection {
public:
BaseLidarObstacleDetection() = default;
virtual ~BaseLidarObstacleDetection() = default;
virtual bool Init(
const LidarObstacleDetectionInitOptions &options = LidarObstacleDetectionInitOptions()) = 0; // 初始化接口
virtual LidarProcessResult Process(const LidarObstacleDetectionOptions &options, const std::shared_ptr<apollo::drivers::PointCloud const> &message, LidarFrame *frame) = 0; // 处理接口
virtual LidarProcessResult Process(
const LidarObstacleDetectionOptions& options,
LidarFrame* frame) = 0;
virtual std::string Name() const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(BaseLidarObstacleDetection); // 禁止拷贝构造与拷贝赋值
}; // class BaseLidarObstacleDetection
PERCEPTION_REGISTER_REGISTERER(BaseLidarObstacleDetection); // 生成 BaseLidarObstacleDetection 的客户端代码
#define PERCEPTION_REGISTER_LIDAROBSTACLEDETECTION(name) \
PERCEPTION_REGISTER_CLASS(BaseLidarObstacleDetection, name) // 生成 name 具体产品的具体工厂类
BaseLidarObstacleDetection是一个抽象基类,其内部含有三个 public 的对外接口:Init、Process 和 Name,通过使用宏定义 DISALLOW_COPY_AND_ASSIGN 来禁止拷贝构造与拷贝赋值,DISALLOW_COPY_AND_ASSIGN 定义在 apollo/cyber/common/macros.h 中:
#define DISALLOW_COPY_AND_ASSIGN(classname) \
classname(const classname &) = delete; \
classname &operator=(const classname &) = delete;
同时可以发现,BaseLidarObstacleDetection类定义的外面调用了一个宏定义 PERCEPTION_REGISTER_REGISTERER,并定义了一个新的宏定义 PERCEPTION_REGISTER_LIDAROBSTACLEDETECTION来间接调用另一个宏定义 PERCEPTION_REGISTER_CLASS。
PERCEPTION_REGISTER_REGISTERER 用于生成工厂方法的客户端代码,PERCEPTION_REGISTER_CLASS 用于生成工厂方法的具体工厂类,它们都定义在 apollo/modules/perception/lib/registerer/registerer.h 中:
namespace apollo {
namespace perception {
namespace lib {
// idea from boost any but make it more simple and don't use type_info.
// 从 boost 库借鉴而来的 Any 类实现,可表示任意的抽象产品
class Any {
public:
Any() : content_(NULL) {}
template <typename ValueType>
explicit Any(const ValueType &value)
: content_(new Holder<ValueType>(value)) {}
Any(const Any &other)
: content_(other.content_ ? other.content_->Clone() : nullptr) {}
~Any() { delete content_; }
template <typename ValueType>
ValueType *AnyCast() {
return content_ ? &(static_cast<Holder<ValueType> *>(content_)->held_)
: nullptr;
}
private:
class PlaceHolder {
public:
virtual ~PlaceHolder() {}
virtual PlaceHolder *Clone() const = 0;
};
template <typename ValueType>
class Holder : public PlaceHolder {
public:
explicit Holder(const ValueType &value) : held_(value) {}
virtual ~Holder() {}
virtual PlaceHolder *Clone() const { return new Holder(held_); }
ValueType held_;
};
PlaceHolder *content_;
};
// 可用于生产任意抽象产品的抽象工厂类
class ObjectFactory {
public:
ObjectFactory() {}
virtual ~ObjectFactory() {}
virtual Any NewInstance() { return Any(); } // 产品生产接口
ObjectFactory(const ObjectFactory &) = delete;
ObjectFactory &operator=(const ObjectFactory &) = delete;
private:
};
typedef std::map<std::string, ObjectFactory *> FactoryMap; // 派生类(具体产品)工厂指针映射
typedef std::map<std::string, FactoryMap> BaseClassMap; // 抽象基类(抽象产品)映射
BaseClassMap &GlobalFactoryMap(); // 获取 static 的抽象基类映射
// 结合 BaseClassMap 和 FactoryMap 获取指定基类对应的所有派生类
bool GetRegisteredClasses(
const std::string &base_class_name,
std::vector<std::string> *registered_derived_classes_names);
} // namespace lib
} // namespace perception
} // namespace apollo
// 客户端代码
// 为指定的抽象产品类生成一个注册器类,包含用于生产产品实例的静态方法
// 宏定义中,## 用于连接两个记号,# 用于将宏参数转换为字符串
#define PERCEPTION_REGISTER_REGISTERER(base_class) \
class base_class##Registerer { \
typedef ::apollo::perception::lib::Any Any; \
typedef ::apollo::perception::lib::FactoryMap FactoryMap; \
\
public: \
static base_class *GetInstanceByName(const ::std::string &name) { \
FactoryMap &map = \
::apollo::perception::lib::GlobalFactoryMap()[#base_class]; \
FactoryMap::iterator iter = map.find(name); \
if (iter == map.end()) { \
for (auto c : map) { \
AERROR << "Instance:" << c.first; \
} \
AERROR << "Get instance " << name << " failed."; \
return nullptr; \
} \
Any object = iter->second->NewInstance(); \
return *(object.AnyCast<base_class *>()); \
} \
static std::vector<base_class *> GetAllInstances() { \
std::vector<base_class *> instances; \
FactoryMap &map = \
::apollo::perception::lib::GlobalFactoryMap()[#base_class]; \
instances.reserve(map.size()); \
for (auto item : map) { \
Any object = item.second->NewInstance(); \
instances.push_back(*(object.AnyCast<base_class *>())); \
} \
return instances; \
} \
static const ::std::string GetUniqInstanceName() { \
FactoryMap &map = \
::apollo::perception::lib::GlobalFactoryMap()[#base_class]; \
CHECK_EQ(map.size(), 1U) << map.size(); \
return map.begin()->first; \
} \
static base_class *GetUniqInstance() { \
FactoryMap &map = \
::apollo::perception::lib::GlobalFactoryMap()[#base_class]; \
CHECK_EQ(map.size(), 1U) << map.size(); \
Any object = map.begin()->second->NewInstance(); \
return *(object.AnyCast<base_class *>()); \
} \
static bool IsValid(const ::std::string &name) { \
FactoryMap &map = \
::apollo::perception::lib::GlobalFactoryMap()[#base_class]; \
return map.find(name) != map.end(); \
} \
};
// 具体工厂类
// 在 Perception 功能模块 .so 动态库文件加载期间,被 __attribute__((constructor))
// 修饰的函数会优先执行,创建具体产品类对应的具体工厂指针,并将其映射到相应的 FactoryMap 中
#define PERCEPTION_REGISTER_CLASS(clazz, name) \
namespace { \
class ObjectFactory##name : public apollo::perception::lib::ObjectFactory { \
public: \
virtual ~ObjectFactory##name() {} \
virtual ::apollo::perception::lib::Any NewInstance() { \
return ::apollo::perception::lib::Any(new name()); \
} \
}; \
__attribute__((constructor)) void RegisterFactory##name() { \
::apollo::perception::lib::FactoryMap &map = \
::apollo::perception::lib::GlobalFactoryMap()[#clazz]; \
if (map.find(#name) == map.end()) map[#name] = new ObjectFactory##name(); \
} \
} // namespace
在感知子功能模块 .so 动态库文件加载期间,下面这条语句
PERCEPTION_REGISTER_REGISTERER(BaseLidarObstacleDetection);
将为 BaseLidarObstacleDetection类创建客户端类 BaseLidarObstacleDetectionRegisterer,通过调用 BaseLidarObstacleDetection::GetInstanceByName 可以获得指定具体产品类 LidarObstacleDetection 的实例指针,问题在于,LidarObstacleDetection的具体工厂是什么时候创建的?
打开 apollo/modules/perception/lidar/app/lidar_obstacle_detection.cc,最后有这样一条语句:
PERCEPTION_REGISTER_LIDAROBSTACLEDETECTION(LidarObstacleDetection);
结合上面的分析,该语句会被替换为:
// 调用 apollo/modules/perception/lidar/lib/interface/base_lidar_obstacle_detection.h 定义的宏PERCEPTION_REGISTER_LIDAROBSTACLEDETECTION
PERCEPTION_REGISTER_CLASS(BaseLidarObstacleDetection, LidarObstacleDetection)
具体展开:
// 用于生成工厂方法的具体工厂类
namespace {
class ObjectFactoryLidarObstacleDetection: public apollo::perception::lib::ObjectFactory {
public:
virtual ~ObjectFactoryLidarObstacleDetection() {}
virtual ::apollo::perception::lib::Any NewInstance() {
return ::apollo::perception::lib::Any(new LidarObstacleDetection());
}
};
__attribute__((constructor)) void RegisterFactoryLidarObstacleDetection() {
::apollo::perception::lib::FactoryMap &map =
::apollo::perception::lib::GlobalFactoryMap()["BaseLidarObstacleDetection"];
if (map.find("LidarObstacleDetection") == map.end()) map["LidarObstacleDetection"] = new ObjectFactoryLidarObstacleDetection(); // 创建具体工厂指针,并将其多态地映射到相应的 FactoryMap 中
}
} // namespace
ObjectFactoryLidarObstacleDetection即为 LidarObstacleDetection对应的具体工厂类,RegisterFactoryLidarObstacleDetection函数由于被 attribute((constructor)) 属性修饰,因而会在 Perception 功能模块 .so 动态库文件加载期间被执行,完成 LidarObstacleDetection类具体工厂指针的创建(相应的 new 语句),并将其多态地映射到相应的 FactoryMap 中。最后,通过调用客户端方法 BaseLidarObstacleDetection::GetInstanceByName 即可获得 LidarObstacleDetection类的实例指针。
apollo/modules/perception/onboard/component/detection_component.cc
lidar::BaseLidarObstacleDetection *detector = lidar::BaseLidarObstacleDetectionRegisterer::GetInstanceByName(detector_name_); // 工厂模式,调用宏定义类的静态方法获取类LidarObstacleDetection的实例指针
更多推荐


所有评论(0)