c++ 多格式解析的设计方向

uqjltbpv  于 2022-11-19  发布在  其他
关注(0)|答案(1)|浏览(128)

我正在编写一个应用程序来解析文本文件中的行。问题是我需要能够根据运行时设置的变量加载不同的例程。我不能更改传入文件的格式。

int intFormat = 1; //Loaded from INI file

void __fastcall TForm1::Button1Click(TObject *Sender) {
    myFileConverstion *myFC;
    switch(intFormat) {
        case 1:
            myFC = new FileConverstionCompanyA(); 
        case 2:
            myFC = new FileConverstionCompanyB();
    }
    myFileConverstion->Execute("fileName");
}

->Execute()中,我将调用private(或protected)方法来进行解析。
最好的OOP方法是什么?

  • 创建虚拟对象,即:myFileConverstion-然后从CompanyABC等的那个继承。
  • 编写myFileConverstion,其中包含所有常用方法(private/protected)和一个虚拟的Execute()。然后,只需更改各个“公司”的Execute()内部结构即可。

我在寻求指导。
我还没试过,我还在计划阶段。

sr4lhrrt

sr4lhrrt1#

也有可能通过std:.function将它们插入到某种查找Map中来实现整个过程。下面是一些例子:

#include <functional>
#include <iostream>
#include <unordered_map>

class FileConverter
{
    using convert_engine_t = std::function< bool( const std::string& ) >;
    std::unordered_map< size_t, convert_engine_t > engines;
    convert_engine_t *activeEngine { nullptr };
public:
    template < class T >
    auto addEngine( size_t id, T && routine ) -> void
    {
        engines.emplace( id, std::forward< T >( routine ) );
    }

    auto setActiveEngine( size_t id ) -> bool
    {
        const auto iterFound = engines.find( id );

        if ( iterFound == engines.end() )
            return false;

        activeEngine = &iterFound->second;
        return true;
    }

    auto convert( const std::string fileName ) -> bool
    {
        if ( !activeEngine || !( *activeEngine ) )
            return false;

        return ( *activeEngine )( fileName );
    }
};

int main()
{
    struct MyConvertingEngineA
    {
        auto operator()( const auto& fn ) {
           std::cout << "Doing A" << std::endl; return true;
        }
    };

    auto myConvertingEngineB = []( const auto& fn ) {
        std::cout << "Doing B" << std::endl; return true;
    };

    FileConverter myFC;
    myFC.addEngine( 1, MyConvertingEngineA() );
    myFC.addEngine( 2, std::move( myConvertingEngineB ) );
    myFC.addEngine( 8, []( const auto& fn ){ std::cout << "Doing C" << std::endl; return true; } );

    myFC.setActiveEngine( 1 );
    myFC.convert( "MyFileA1" );
    myFC.convert( "MyFileA2" );

    myFC.setActiveEngine( 2 );
    myFC.convert( "MyFileB" );

    myFC.setActiveEngine( 8 );
    myFC.convert( "MyFileC" );

    myFC.setActiveEngine( 7 ); // Will fail, old engine will remain active
    return 0;
}

输出:

做A
做A
执行B
执行C

关于代码的一些说明:

addEngine函数使用带有转发引用和完美转发的模板来提供尽可能广泛的接口。引擎被复制或移动到这里,这取决于传递的引用类型。引擎以“可调用对象”的形式传递。可以添加不同类型的函数或lambda。甚至(如示例中所示)只要满足std::function的函数签名,就可以传递泛型lambda(自动参数)。这节省了另一个字符串类型的冗余规范。如果您有大型复杂的引擎,请使用单独的类而不是lambda来保持较小的局部作用域
如果你不想有任何继承,共享的解析器功能也可以通过智能pounter传递给各自的引擎。

class EngineA
    {
        std::shared_ptr< ParserCore > parserCore;
    public:
        EngineA( std::shared_ptr< ParserCore > parserCoreParam ) : 
            parserCore( std::move( parserCoreParam ) ) 
        {}
        
        auto operator()( const auto& fn ) {
           std::cout << "Doing A" << std::endl; return true;
           // -> parserCore->helperFuncForABC() ....;
        }
    };

相关问题