【问题标题】:Data mapping : from "any" class to a generic key value map (C++)数据映射:从“任何”类到通用键值映射 (C++)
【发布时间】:2012-12-28 10:02:26
【问题描述】:

出于日志记录的目的,我想将各种类(为此我想要一种通用方法)调整为键值字典:这可以看作是“键值序列化”。

假设键是预定义的,并且根据我们想要适应的输入类,每个值可能对应于一个特定的属性。 值总是可以封装到 std::string 中。

这将是我的方法:

创建一个可以转储到数据库中的适配器类

#include <keys.h> // enum with possible keys, defining type Key_t

namespace generic
{
    class Adapter
    {
        public:
            Adapter();
            virtual ~Adapter();
            virtual void init() = 0;

        private:
            std::map<Key_t, std::string> _data;
    }
}

对于每个可能的客户端,在其命名空间中专门化适配器类,假设它与任何客户端的特定业务对象模型是朋友(以便轻松访问属性),并且它通过其构造函数中的 const 引用接收此类模型的实例

例如

#include <generic/Adapter.h>

#include <client1/bom1.h>
#include <client1/bom2.h>
...
#include <client1/bomN.h>

namespace client1
{
    class Adapter : public generic::Adapter
    {
        public:
            Adapter(const Bom1& bom1,
                    const Bom2& bom2,
                    const BomN& bomN)
            : _bom1(bom1), _bom2(bom2), _bomN(bomN)
            {}

            void init()
            {
                // Explicit data mapping in here
                 _map[NAME] = _bom1._name;
                 _map[TITLE] = _bom2._title;
                 ....
                 ....
            }

        private:
            Bom1 _bom1;
            Bom2 _bom2;
            BomN _bomN;
      }
}

您如何看待这种方法? 在 c++ 中是否有更通用的方法来实现这一点? 你的设计是什么?

谢谢!

更新

当一个新的客户端被实现时,日志引擎不应该改变:这就是为什么适配逻辑应该分布在客户端而不是在日志引擎的核心中实现。 只有在需要新键时才会更新日志引擎(这可能意味着数据库结构发生变化)。

【问题讨论】:

  • 你可以只使用模板化的日志功能...
  • 我也在考虑这个方法,但我有很多客户,每个客户都有很多数据要映射:我想避免将所有数据映射集中到一个大模板中需要为每个客户专门化的功能(每个客户都有自己不同的 BOM);我更喜欢在客户端分发映射。

标签: c++ serialization adapter key-value


【解决方案1】:

我会存储键和值的序列化字符串。
Here 我正在使用ldbSerialize 方法,该方法默认使用 boost 序列化,无需创建新类即可轻松专门化。对于每一种新类型的键,只需添加一个新的专精:

template <> inline void ldbSerialize<Key32> (string& bytes, const Key32& key) {
  bytes += key.whatever();
}

【讨论】:

  • 在这种情况下不只是序列化吗?我可能遗漏了一些东西,但是,关键是我需要将不同的结构序列化为某种静态和预定义的数据映射。这种方法可以用于序列化部分,但是适应呢?
  • 好的,根据您的用例量身定制,这可能看起来像 template &lt;&gt; inline void logMe&lt;Key32&gt; (std::map&lt;Key_t, std::string&gt;&amp; data, const Key32&amp; key) {data[NAME] = key._name;};关键是要有一个默认的序列化方法并将其专门用于新客户。
  • 这对简单的“logMe”函数重载有什么好处?
  • 优势 (IMO) 是您可以拥有一个默认的 logMe,而无需从某个基类派生您的客户端。对于客户端作者来说,它的侵入性更小,更容易实现。 (在我的情况下,默认函数使用 Boost 序列化)。但是,既然您在上面写道,您“希望避免将所有数据映射集中到一个大模板函数中”,那么您的初始方法可能是最好的,尽管我没有从您的示例中看到大的“init”方法会有什么不同来自一个大的专业“logMe”功能。
  • 你可以有模板化的辅助函数,例如logUsualFields,您可以从 logMe 专业中调用它。这样你就可以分散序列化。 IMO 它比弄乱继承更干净。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
  • 1970-01-01
  • 2013-05-04
  • 1970-01-01
  • 2020-05-16
  • 2017-07-24
  • 2021-09-26
相关资源
最近更新 更多