Codec2之建造者模式

Codec2的组件在参数配置上,采用了建造者模式,以下我们简单分析该模式的运用过程。
组件在初始化时,通过addParameter接口配置默认参数。

  class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {public:explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper): SimpleInterface<void>::BaseParams(helper,COMPONENT_NAME,C2Component::KIND_DECODER,C2Component::DOMAIN_VIDEO,MEDIA_MIMETYPE_VIDEO_AVC) {noPrivateBuffers(); // TODO: account for our buffers herenoInputReferences();noOutputReferences();noInputLatency();noTimeStretch();// TODO: Proper support for reorder depth.addParameter(DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY).withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay)).withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)}).withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps).build());........//省略其他addParameter}

addParameter的参数是ParamHelper类型,这个参数的构建采用了建造者模式。

什么是建造者模式?这里如何运用了建造者模式?

首先,理解什么是建造者模式,不如直接阅读《秒懂设计模式之建造者模式》,这篇文章非常通俗易懂地讲解了建造者模式的应用场景与两种构建方法。在此简单总结一下这篇文件的要点。

使用场景

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

解决的问题

当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象,
第一种,折叠构造函数模式(telescoping constructor pattern ),第二种,Javabean 模式。
第一种主要是使用及阅读不方便。第二种方式在构建过程中对象的状态容易发生变化,造成错误。因为类中的属性是分步设置的,所以就容易出错。为了解决这两个痛点,builder模式就横空出世了。

如何实现(以Computer的构建为例)

  1. 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
  2. 在Computer中创建一个private的构造函数,参数为Builder类型
  3. 在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram。
  4. 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例
  5. 在Builder中创建一个build()方法,在其中构建Computer的实例并返回

如何使用

在客户端使用链式调用,一步一步的把对象构建出来。

其次,我们来看一下Codec2中,组件是如何运用建造者模式来配置参数的。

addParameter的参数是ParamHelper类型,它的定义为:

DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY).withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay)).withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)}).withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps).build()

DefineParam方法是C2InterfaceHelper的静态方法。

class C2InterfaceHelper {public:template<typename T>static ParamBuilder<T> DefineParam(std::shared_ptr<T> &param, C2StringLiteral name) {return ParamBuilder<T>(param, name);}
}

它返回ParamBuilder对象。根据mActualOutputDelay的定义:

template<>
class SimpleC2Interface<void> {public:std::shared_ptr<C2PortActualDelayTuning::output> mActualOutputDelay;
}

ParamBuilder对象扩展为ParamBuilder< C2PortActualDelayTuning::output >对象。

ParamBuilder类定义在C2InterfaceHelper.h中,它具有若干个方法,在addParameter的参数定义中链式调用。

   /*** Templated move builder class for a parameter helper.*/template<typename T>class C2_HIDE ParamBuilder : private ParamHelper {public:/** Construct the parameter builder from minimal info required. */ParamBuilder(std::shared_ptr<T> &param, C2StringLiteral name): ParamHelper(param, name, C2StructDescriptor((T*)nullptr)),mTypedParam(&param) {attrib() = attrib_t::IS_PERSISTENT;}//......省略/** Adds default value. Must be added exactly once. */inline ParamBuilder &withDefault(std::shared_ptr<T> default_) {// CHECK(!mDefaultValue);// WARN_IF(!default_); // could be nullptr if OOM// technically, this could be in the parent*mTypedParam = std::shared_ptr<T>(T::From(C2Param::Copy(*default_).release()));setDefaultValue(default_);std::shared_ptr<T> *typedParam = mTypedParam;setGetter([typedParam](bool) -> std::shared_ptr<C2Param> {return std::static_pointer_cast<C2Param>(*typedParam);});return *this;}/** Adds default value. Must be added exactly once. */inline ParamBuilder &withDefault(T *default_) {return withDefault(std::shared_ptr<T>(default_));}/** Adds all fields to this parameter with their possible values. */inline ParamBuilder &withFields(std::vector<C2ParamFieldValues> &&fields_) {setFields(std::move(fields_));return *this;}/*** Adds a constant value (also as default). Must be added exactly once.** Const parameters by definition have no dependencies.*/inline ParamBuilder &withConstValue(std::shared_ptr<T> default_) {//...... 省略return withDefault(default_);}/** Adds constant value (also as default). Must be added exactly once. */inline ParamBuilder &withConstValue(T *default_) {return withConstValue(std::shared_ptr<T>(default_));}template<typename ... Deps>inline ParamBuilder &withSetter(C2R (*fn)(bool, C2P<T> &, const C2P<Deps> &...), std::shared_ptr<Deps>& ... deps) {//...... 省略return *this;}//返回的是ParamHelper类的方法build()inline std::shared_ptr<ParamHelper> build() {return ParamHelper::build();}protected:std::shared_ptr<T> *mTypedParam;};

我们看一下ParamHelper类的方法build()的定义。

//C2InterfaceHelper.cpp
std::shared_ptr<C2InterfaceHelper::ParamHelper> C2InterfaceHelper::ParamHelper::build() {mImpl->build();return std::make_shared<C2InterfaceHelper::ParamHelper>(std::move(*this));
}

它返回的是C2InterfaceHelper::ParamHelper类型的对象。这个类型的对象也就是addParameter所需要的入参类型对象。

//C2InterfaceHelper.cpp
void C2InterfaceHelper::addParameter(std::shared_ptr<ParamHelper> param) {std::lock_guard<std::mutex> lock(mMutex);mReflector->addStructDescriptor(param->retrieveStructDescriptor());c2_status_t err = param->validate(mReflector);if (err != C2_CORRUPTED) {_mFactory->addParam(param);// run setter to ensure correct valuesbool changed = false;std::vector<std::unique_ptr<C2SettingResult>> failures;(void)param->trySet(param->value().get(), C2_MAY_BLOCK, &changed, *_mFactory, &failures);}
}

以上就是Codec2组件在参数配置上采用建造者模式的过程,想法很好,但是诸如C2PortActualDelayTuning::output之类的参数定义过于复杂,实在很不友好,不如OpenMAX的标准来得简单快乐。不信?你来看一下以下这个宏定义,感受一下谷歌工程师的炫技与对我们普通开发者的技术暴打。

//C2InterfaceHelper.h
/*** Creates a C2ParamFieldValuesBuilder class for a field of a parameter** \param spParam a configuration parameter in an interface class subclassed from C2InterfaceHelper.* \param field   a field of such parameter*/
#define C2F(spParam, field) \C2ParamFieldValuesBuilder< \typename _c2_reduce_enum_to_underlying_type< \typename std::remove_reference< \typename std::remove_extent< \decltype(spParam->field)>::type>::type>::type>( \C2ParamField(spParam.get(), &spParam->field))

Codec2之建造者模式相关推荐

  1. GOF23设计模式(创建型模式)建造者模式

    使用场景: 我们要建造一个复杂的产品,比如生产一辆汽车.一部手机,这都是由很多零部件组成的,这时候就需要用到我们的建造者模式,将每个零部件分别生产,然后再装配~~ 以下,我将以一个手机的生产过程为实例 ...

  2. 设计模式 之美 -- 建造者模式

    文章目录 1. 解决问题 2. 应用场景 3. 实现 C语言实现 C++实现 4. 缺点 1. 解决问题 描述如下场景: 类的数据成员很多(8个以上),当我们进行初始化的时候放在初始化列表中,影响类的 ...

  3. 设计模式之建造者模式(生成器模式、Builder)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...

  4. 动态表单构建器——建造者模式

    在编写一个弹出框时,它可以包含确定按钮,取消按钮,标题栏,关闭按钮,最小化按钮,内容,最大化按钮等内容,但这些内容在不同的需求下又不是必须存在的,不同的需求需要对这些组件自由组合,显然每次组合都要重复 ...

  5. Python设计模式-建造者模式

    Python设计模式-建造者模式 代码基于3.5.2,代码如下; #coding:utf-8 #建造者模式 class Burger():name = ""price = 0.0d ...

  6. 设计模式-建造者模式(05)

    定义 建造者模式(Builder Pattern)也叫做生成器模式.英文原话是:Separate the construction of a complex object from its repre ...

  7. php设计模式 - 建造者模式

    为什么80%的码农都做不了架构师?>>>    <?php /*** 建造者模式* * 将一个复杂对象的构建与它的表示分离,使用同样的构建过程可以创建不同的表示 */ clas ...

  8. java中自造类是什么意思_Java建造者模式是什么?如何实现?(附代码)

    本篇文章给大家带来的内容是关于Java建造者模式是什么?如何实现?(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 建造者模式 一.什么是建筑者模式? 建造者模式(Build ...

  9. 建造者模式java_java设计模式3——建造者模式

    java设计模式3--建造者模式 1.建造者模式介绍: 建造者模式属于创建型模式,他提供了一种创建对象得最佳方式 定义: 将一个复杂对象的构建和与它的表示分离,使得同样的构建过程可以创建不同的表示 主 ...

最新文章

  1. 字节跳动客户开发_实习|字节跳动 客户端实习生 1-5面 面经
  2. php在页面循环输出标签,自定义页面循环
  3. vim的介绍与常用的命令
  4. FLV封装格式的分析
  5. fsk调制解调实验报告 matlab,基于MATLAB的-FSK调制与解调-通信原理实验
  6. [2018.07.10 T2]不回文
  7. Video Extractor监控视频侦查取证分析系统
  8. 【我的OpenGL学习进阶之旅】学习OpenGL ES 3.0 的实战 Awsome Demo (上)
  9. 《Machine Learning in Action》—— 白话贝叶斯,“恰瓜群众”应该恰好瓜还是恰坏瓜
  10. 51单片机数码管显示学习笔记
  11. java 把ascll转换成char_java中 怎么把一个ascii转换成字符串
  12. 2022第十二届中国电子文件管理论坛嘉宾揭晓
  13. MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors
  14. ML:从工程化思维分析—机器学习团队十大角色的简介(背景/职责/产出物):产品经理、项目经理、业务咨询顾问、数据科学家、ML研究员、数据工程师、ML工程师、DevOps/软件开发/交付工程师
  15. Eclipse导出JavaDoc中文乱码问题解决
  16. compare和compareTo方法的区别
  17. Pregel: A System for Large-Scale Graph Processing
  18. VMware Workstation Player 找不到共享文件夹的解决方法
  19. 气和血1:生命在于气血
  20. 开始使用linggle

热门文章

  1. 数据结构与算法复习:一
  2. Canvas 填充渐变
  3. intellij html 插件,解决intellij idea中使用live edit插件不能在chrome即时显示css变化的方法(html可以)...
  4. 如何使用网页在线打开.Xmind文件(思维导图文件)和建模文件(.SLDPRT文件和.SLDASM文件)
  5. python开发mbus程序_Mbus 2019(水表校验程序)V2.1 最新版
  6. Ubuntu 16.04 开启BBR加速
  7. Python股票处理之四_股票筛选
  8. 制作网页头部固定悬浮的导航栏
  9. bim 水利枢纽 运维_BIM水坝工程技术案例:那棱格勒河水利枢纽工程BIM应用汇报...
  10. 交互媒体专题设计——疫情模拟