`

C++ Plug-in 技术的一些深度思考(1)

阅读更多

C++ Plug-in 技术的一些深度思考(2)

 

 

最近,忙于思考如何重构一个Unix系统。这个系统是由C++写的,重构的思路是希望能够抽取出一些公共的东西,作为Core。另外一些东西做成Plug-in。这样以后如果客户的规范更新了,我们只需要增加修改Plug-in就好了,Core的部分不需要再修改。

 

      要满足这个要求,有些基本的原则:

      [1] Core里面所有的东西不能依赖Plug-in里面。这种依赖可以理解为Build(Compiler + Link)Core里面模块的时候,不需要用到Plug-in里面的头文件或者object文件;

      [2] 部署的时候,可以不用重新部署Core。只需要Update Plug-in,就可以获得新功能。

      [3] 现有代码最好能够最大程度的复用。 

       因为这些要求,对C++设计编码在大型系统中的使用,有了一些新的体会和认识。为了简化问题,我抽象了一个简单的例子。

 

       有这样一个需求: 给定一个整数数组,我们需要对这个数组作些运算,这个运算现在看到的有求和,求积,未来可以增加运算规则,譬如求最大值,最小值,平均值等等。现在不能预测未来需要那些运算,系统需要扩展的能力。

 

       首先来看看运用面向对象和工厂模式给出的初始设计。

       我们有一个ICalc的借口,接口里唯一一个需要Override的函数是:  virtual void calc(int *p, size_t size, int *result) = 0  这里说唯一是从设计角度考虑的,因为它本身的析构函数也是纯虚函数。另一方面,这个函数没有要求是const的,这个不会影响我们的讨论。因为现有系统中并没有一致的使用const,所以我们设计这个接口的时候,没有把const考虑进去。

         接下来,我们设计两个实体类CalcAdd和CalcMul,当然它们都Override了calc这个方法。我们又设计了一个CalcFactory,它有个静态函数getCalc(string calcType)。通过calcType的值,返回正确的Calc类型。



目录结构 

 

// include/ICalc.h
#ifndef _ICALC_H_
#define _ICALC_H_

#include <stdlib.h>

class ICalc
{
    public:
        virtual void calc(int *start, size_t size, int *result) = 0;
        virtual ~ICalc() = 0;
};

#endif //_ICALC_H_

 

//include/CalcFactory.h
#ifndef _CALCFACTORY_H_
#define _CALCFACTORY_H_

#include <string>

#include "ICalc.h"

class CalcFactory
{
    public:
        static ICalc* getCalc(std::string calcType);
};

#endif //_CALCFACTORY_H_

 

  

//include/CalcAdd.h
#ifndef _CALCADD_H_
#define _CALCADD_H_

#include "ICalc.h"

class CalcAdd : public ICalc
{
    public:
        virtual void calc(int *start, size_t size, int *result);
        virtual ~CalcAdd();
};


#endif //_CALCADD_H_

        

    给纯续函数提供函数体是可以的,在这种情况下也是必需的。

#include "../include/ICalc.h"

ICalc::~ICalc(){ }

   

   

// src/CalcFactory.cpp
#include "../include/CalcFactory.h"
#include "../include/CalcAdd.h"
#include "../include/CalcMul.h"

using std::string;

ICalc* CalcFactory::getCalc(string calcType)
{
  if ("Add" == calcType)
  {
    return new CalcAdd;
  }
  else if ("Mul" == calcType)
  {
    return new CalcMul;
  }
  else
  {
    return 0;
  }
}

  

 

// src/CalcAdd.cpp
#include "../include/CalcAdd.h"

void CalcAdd::calc(int *p, size_t size, int *result)
{
    for (size_t i = 0 ; i < size; ++i)
    {
        (*result) += p[i];
    }
}

CalcAdd::~CalcAdd() { }

 

// src/main.cpp
#include <iostream>
#include <string>

#include "../include/CalcFactory.h"
#include "../include/ICalc.h"

using namespace std;

int arr[] = { 1, 2, 3, 4, 5, 6 };
int result; // result = 0

int main(int argc,char* argv[])
{
    if (argc < 2)
    {
        cerr << "Usage: calc Add|Mul" << endl;
        return -1;
    }
    if (string("Add") == argv[1])
    {
        result = 0;
    }
    else if (string("Mul") == argv[1])
    {
        result = 1;
    }
    ICalc *calc = CalcFactory::getCalc(argv[1]);
    if (!calc)
    {
      cerr << "Fail to calc." << endl;
      return -2;
    }
    calc->calc(arr, sizeof(arr)/sizeof(int), &result);
    cout << "result = " << result << endl;
    delete calc;
    return 0;
}

    

 

               大致的程序如上述,上面没有给出CalcMul.h和CalcMul.cpp。因为这个和CalcAdd完全一致。大家可以下载v1.tar.bz2看最初设计的源代码。大家可以使用make -f Makefile.(mac|sun|lnx) all Build整个系统,最后会在bin下面生成一个可执行文件calc,运行就可以看到结果。

          可以看到,这个版本其实是个不错设计的。因为如果我们要增加一个求最小值的算法,只需要设计一个CalcMin,实现ICalc接口,重新修改CalcFactory的getCalc函数,增加一个“Min”的分支,就OK了。这个设计也符合开闭原则。就是对修改开放,对整个工作流的修改是关闭的。可是,这样的设计还是有几个问题:

[1] CalcFactory.obj依赖于CalcAdd.h,CalcMul.h。如果增加一个新的算法,这个文件必须重新修改,编译,链接。

[2] calc虽然不依赖于CalcAdd.h,CalcMul.h。换言之,如果CalcAdd修改了,calc不需要重新编译,但是却需要重新链接。因为calc需要CalcAdd.o, CalcMul.o。

基于这两点,我们没有办法把CalcAdd这样的算法做成Plug-in。因为更新Plug-in,我的Core程序也需要更新。很多时候这不是一个严重的问题,但是有时候我们确实需要简单的更新Plug-in。因为如果只更新Plug-in,我们可以减少很多Core程序测试的时间和工作量。这个在大型程序带来的价值是巨大的。于是,我们继续改进我们的设计。

 

C++ Plug-in 技术的一些深度思考(2)

  • 大小: 14.4 KB
分享到:
评论

相关推荐

    IDA_plug-in_writing_in_C_or_C++.rar

    IDA_plug-in_writing_in_C_or_C++, 中文和英文两个。IDA_plug-in_writing_in_C_or_C++

    GNU ARM Eclipse Plug-in

    《GNU ARM Eclipse Plug-in:为Eclipse开发环境增添ARM支持》 GNU ARM Eclipse Plug-in是专为Eclipse集成开发环境(IDE)设计的一款扩展插件,由开发者ilg-ul和justxi共同贡献。该插件的主要目的是为了在Eclipse...

    Designing Software Synthesizer Plug-Ins in C++

    Bridging the gap from theory to programming, Designing Software Synthesizer Plug-Ins in C++ For RackAFX, VST3 and Audio Units contains complete code for designing and implementing software ...

    Visual C++ 2015-2019 Redistributable.zip

    开发者使用Visual C++编写的应用程序,通常会依赖于一些特定的库文件,这些库文件在用户计算机上可能并未预装。因此,Visual C++ Redistributable就应运而生,它的主要功能就是提供这些必要的运行时库,使得用户无需...

    Microsoft Visual C++ 2015-2019 运行库合集,包含32位64位

    1. "Microsoft Visual C++ 2015-2019 Redistributable - 14.26.28720.3 x64.exe" 是64位版本的安装程序,提供版本号为14.26.28720.3的运行库,适用于64位Windows系统。 2. "Microsoft Visual C++ 2015-2019 ...

    Microsoft Visual C++ 2015-2022 Redistributable (x64)

    1. **运行时库**:Visual C++ Redistributable 包含了运行时库文件,这些文件在应用程序运行时负责处理内存管理、异常处理、线程管理等任务,是程序执行所必需的。 2. **多版本合并**:2015-2022表明这个包集成了多...

    gcc-c++-4.4.7-16.el6.x86_64.rpm

    warning: gcc-c++-4.4.7-3.el6.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID c105b9de: NOKEY error: Failed dependencies: gcc = 4.4.7-3.el6 is needed by gcc-c++-4.4.7-3.el6.x86_64 libstdc++ = 4.4.7-...

    S60_Platform_ECom_Plug-in_Examples_v2_0_en

    《S60 Platform ECom Plug-in Examples v2.0_en:Symbian手机程序开发实践指南》 在移动操作系统领域,Symbian以其强大的功能和广泛的设备支持,曾一度成为智能手机开发的重要平台。"S60 Platform ECom Plug-in ...

    C++编程思想-Thinking in C++ 11

    C++编程思想-Thinking in C++

    gcc-c++-3.4.6-3.1.x86_64.rpm

    gcc-c++-3.4.6-3.1.x86_64.rpm

    基于libmodbus开源库 C++ modbus-rtu通信测试程序源码

    基于libmodbus开源库 C++ modbus-rtu通信测试程序源码,vs2013平台。此文件为主站程序可实现与从站(从站可以使用Modbus Slave 仿真软件)通信,实现寄存器的读写功能。

    gcc-c++-3.4.6-8.x86_64.rpm

    Linux安装Oracle先决条件gcc-c++-3.4.6-8.x86_64.rpm

    C++ Templates - The Complete Guide英文版.rar

    《C++ Templates - The Complete Guide》是一本深入探讨C++模板技术的专业书籍,它为开发者提供了全面、详尽的模板知识。模板是C++语言中一个强大的特性,它允许我们编写泛型代码,提高代码的复用性和灵活性。这本书...

    C++ Templates The Complete Guide (2nd Edition)

    -Giving guidance on how to use Templates in Modern C++ -For programmers, who just use templates, who provide class and function templates, and who provide generic and foundation libraries -Covering ...

    Plug-in GUI-开源

    【标题】:“Plug-in GUI-开源” 开源软件的精髓在于开放源代码,允许开发者自由查看、使用、修改和分发代码。"Plug-in GUI"项目就是这样一个体现,它旨在为程序员构建一个库,以实现他们应用程序的可换肤界面功能...

    基于C++MFC-RS485串口通信demo-完整版-代码

    以下是一些关键步骤: 1. **创建串口对象**:首先,我们需要在程序中实例化一个`CSerialPort`对象,通常在类的构造函数中完成。 ```cpp CSerialPort m_serialPort; ``` 2. **配置串口参数**:接着,使用`...

    Object-Oriented Programming in C++源程序

    Object-Oriented Programming in C++Object-Oriented Programming in C++Object-Oriented Programming in C++

    compat-gcc-c++-7.3-2.96.128.i386.rpm

    compat-gcc-c++-7.3-2.96.128.i386.rpm

    gcc-c++-4.4.7-4.el6.i686.rpm等

    gcc-c++-4.4.7-4.el6.i686.rpm cpp-4.4.7-4.el6.i686.rpm gcc-4.4.7-4.el6.i686 .rpm libstdc++-devel-4.4.7-4.el6.i686.rpm libstdc++-4.4.7-4.el6.i686.rpm

Global site tag (gtag.js) - Google Analytics