利用“宏元编程”解决重复问题

来源:互联网 发布:如何做淘宝优惠券网站 编辑:程序博客网 时间:2024/06/13 20:57
在一个网元中,存在着各种“受管对象”(Managed Object)。每种“受管对象”都有自己的一组配置数据。比如,一个“学生”对象的配置数据定义如下:
struct Student{   unsigned long  code;   char           name[9];   unsigned char  height;   unsigned short score;};
在“受管对象”配置修改的过程中,如果出了差错,应该可以将配置“回滚”到之前的值。所以,我们定义了如下模版来保存一个配置项。
template <typename T>struct ConfigValue{   ConfigValue(const T& defaultValue)      : changed(false)       , currentValue(defaultValue)      , oldValue(defaultValue)      {}   void set(const T& value)   {      if(currentValue == value) return;      oldValue = currentValue;      currentValue = value;      changed = true;   }   const T& get() const   { return currentValue; }   const T& getOldValue() const   { return changed ? oldValue : currentValue; }   void resetStatus()   { changed = false; }   void revert()   {      if(not changed) return;      currentValue = oldValue;      changed = false;   }   bool isChanged() const   { return changed; }private:   bool changed;   T    currentValue;   T    oldValue;};
基于此模版,我们将“学生”的配置定义为:
struct StudentConfig{   ConfigValue<unsigned long>       code;   ConfigValue<FixedSizeString<8> > name;   ConfigValue<unsigned char>       height;   ConfigValue<unsigned short>      score;};
通过SNMP的客户端,用户可以一次性修改某个“受管对象”的多个配置数据。比如,对于某个“学生”对象,用户可以同时修改他的“身高”和“总成绩”。所以我们定义了如下模版来保存由SNMP客户端而来的某个配置项:
template <typename T>struct OptionalConfigValue{   OptionalConfigValue() : specified(false) {}   void set(const T& value)   {      this->value = value;      specified   = true;   }   void updateTo(ConfigValue<T>& config) const   {      if(specified) config.set(value);   }private:   bool specified;   T    value;};
以“学生”对象为例,相应的SNMP配置结构则定义为:
struct StudentOptionalConfig{   OptionalConfigValue<unsigned long>       code;   OptionalConfigValue<FixedSizeString<8> > name;   OptionalConfigValue<unsigned char>       height;   OptionalConfigValue<unsigned short>      score;};
这样,StudentConfig应该提供一个update接口,来更新来自于SNMP客户端的配置数据。比如:
struct StudentConfig{   StudentConfig()      : code(0)      , name("anon")      , height(170)      , score(0)   {}   void update(const StudentOptionalConfig& config)   {      config.code.updateTo(code);      config.name.updateTo(name);      config.height.updateTo(height);      config.score.updateTo(score);   }   void revert()   {      code.revert();      name.revert();      height.revert();      score.revert();   }   void configDone()   {      code.resetStatus();      name.resetStatus();      height.resetStatus();      score.resetStatus();    }private:   ConfigValue<unsigned long>       code;   ConfigValue<FixedSizeString<8> > name;   ConfigValue<unsigned char>       height;   ConfigValue<unsigned short>      score;};
从上述的实现中,我们能够发现强烈的重复模式:首先,所有的配置信息在不同的地方重复出现,其次,对于不同的配置信息进行相同的处理。

为了解决这样的重复问题,我们首先使用宏来定义“元数据”:
// Student.hDEFINE_CONFIG    (code,     unsigned long,  0)DEFINE_CONFIG    (height,   unsigned char,  170)DEFINE_CONFIG    (score,    unsigned short, 0)DEFINE_STR_CONFIG(name,     8,              "anon")
而“魔法”的关键在于,如何来通过不同的宏定义来“解释”这些元数据。
比如,对于StudentOptionalConfig的定义,我们可以将其代码转化为:
// StudentOptionalConfig.hstruct StudentOptionalConfig{#include <OptionalConfigDef.h>#include "Student.h"};
而OptionalConfig.h的定义为:
// OptionalConfigDef.h////////////////////////////////////////////////#ifdef DEFINE_CONFIG#undef DEFINE_CONFIG#endif#define DEFINE_CONFIG(name, type, defaultValue) \   OptionalConfigValue<type> name;////////////////////////////////////////////////#ifdef DEFINE_STR_CONFIG#undef DEFINE_STR_CONFIG#endif#define DEFINE_STR_CONFIG(name, size, defaultValue) \   OptionalConfigValue<FixedSizeString<size> > name;
类似的,StudentConfig的定义则变为:
// StudentConfig.hstruct StudentConfig{   StudentConfig() :    #include <DefaultValueDef.h>   #include "Student.h"   , dummy(true)   {}   void update(const StudentOptionalConfig& config)   {      #include <UpdateDef.h>      #include "Student.h"   }   void revert()   {      #include <RevertDef.h>      #include "Student.h"   }   void configDone()   {      #include <ConfigDoneDef.h>      #include "Student.h"   }private:   #include <ConfigDef.h>   #include "Student.h"   bool dummy;};
而各个魔法头文件的定义分别为:
// DefaultValueDef.h////////////////////////////////////////////////#ifdef DEFINE_CONFIG#undef DEFINE_CONFIG#endif#define DEFINE_CONFIG(name, type, defaultValue) \   name(defaultValue),////////////////////////////////////////////////#ifdef DEFINE_STR_CONFIG#undef DEFINE_STR_CONFIG#endif#define DEFINE_STR_CONFIG(name, size, defaultValue) \   name(defaultValue),
// UpdateDef.h////////////////////////////////////////////////#ifdef DEFINE_CONFIG#undef DEFINE_CONFIG#endif#define DEFINE_CONFIG(name, type, defaultValue) \   config.name.updateTo(name);////////////////////////////////////////////////#ifdef DEFINE_STR_CONFIG#undef DEFINE_STR_CONFIG#endif#define DEFINE_STR_CONFIG(name, size, defaultValue) \   config.name.updateTo(name);
// CofigDoneDef.h////////////////////////////////////////////////#ifdef DEFINE_CONFIG#undef DEFINE_CONFIG#endif#define DEFINE_CONFIG(name, type, defaultValue) \   name.resetStatus();////////////////////////////////////////////////#ifdef DEFINE_STR_CONFIG#undef DEFINE_STR_CONFIG#endif#define DEFINE_STR_CONFIG(name, size, defaultValue) \   name.resetStatus();
// RevertDef.h////////////////////////////////////////////////#ifdef DEFINE_CONFIG#undef DEFINE_CONFIG#endif#define DEFINE_CONFIG(name, type, defaultValue) \   name.revert();////////////////////////////////////////////////#ifdef DEFINE_STR_CONFIG#undef DEFINE_STR_CONFIG#endif#define DEFINE_STR_CONFIG(name, size, defaultValue) \   name.revert();
// ConfigDef.h////////////////////////////////////////////////#ifdef DEFINE_CONFIG#undef DEFINE_CONFIG#endif#define DEFINE_CONFIG(name, type, defaultValue) \   ConfigValue<type> name;////////////////////////////////////////////////#ifdef DEFINE_STR_CONFIG#undef DEFINE_STR_CONFIG#endif#define DEFINE_STR_CONFIG(name, size, defaultValue) \   ConfigValue<FixedSizeString<size> > name;
有了这些魔法定义文件,每个配置定义文件就呈现除了简单一致的规则,很容易就可以写出一个代码生成器,自动生成相关的代码。下面是一个Python的实现:
import sysoptional_config_template = '''#ifndef __%s_OPTIONAL_CONFIG_H__#define __%s_OPTIONAL_CONFIG_H__struct %sOptionalConfig{   #include <OptionalConfigDef.h>   #include "%s.h"   };#endif'''config_template = '''#ifndef __%s_CONFIG_H__#define __%s_CONFIG_H__struct %sConfig{   %sConfig()   #include <DefaultValueDef.h>   #include "%s.h"   dummy(true)   {}   void update(const %sOptionalConfig& config)   {      #include <UpdateDef.h>      #include "%s.h"   }   void configDone()   {      #include <ConfigDoneDef.h>      #include "%s.h"   }   void revert()   {      #include <RevertDef.h>      #include "%s.h"   }private:   #include <ConfigDef.h>   #include "%s.h"      bool dummy;};#endif'''def write_file(name, suffix, content) :   file = open(name + suffix + ".h", "w")   file.write(content)   file.close()def generate_optional_config(name) :   write_file(name, "OptionalConfig", \      optional_config_template % \          ( name.upper(), name.upper(), name, name))def generate_config(name) :   write_file(name, "Config", \      config_template % \          ( name.upper(), name.upper() \          , name, name, name, name, name, name, name, name))def generate(name) :   generate_optional_config(name)   generate_config(name)def usage() :   print "usage: python config-gen.py config-name"if __name__ == "__main__":   if len(sys.argv) != 2:      usage()      sys.exit(1)   generate(sys.argv[1])

原创粉丝点击