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

在一个网元中,存在着各种“受管对象”(Managed Object)。每种“受管对象”都有自己的一组配置数据。比如,一个“学生”对象的配置数据定义如下:
struct Student
{
   unsigned long  code;
   char           name[9];
   unsigned char  height;
   unsigned short score;
};
在“受管对象”配置修改的过程中,如果出了差错,应该可以将配置“回滚”到之前的值。所以,我们定义了如下模版来保存一个配置项。
template 
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       code;
   ConfigValue > name;
   ConfigValue       height;
   ConfigValue      score;
};
通过SNMP的客户端,用户可以一次性修改某个“受管对象”的多个配置数据。比如,对于某个“学生”对象,用户可以同时修改他的“身高”和“总成绩”。所以我们定义了如下模版来保存由SNMP客户端而来的某个配置项:
template 
struct OptionalConfigValue
{
   OptionalConfigValue() : specified(false) {}

   void set(const T& value)
   {
      this->value = value;
      specified   = true;
   }

   void updateTo(ConfigValue& config) const
   {
      if(specified) config.set(value);
   }

private:
   bool specified;
   T    value;
};
以“学生”对象为例,相应的SNMP配置结构则定义为:
struct StudentOptionalConfig
{
   OptionalConfigValue       code;
   OptionalConfigValue > name;
   OptionalConfigValue       height;
   OptionalConfigValue      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       code;
   ConfigValue > name;
   ConfigValue       height;
   ConfigValue      score;
};
从上述的实现中,我们能够发现强烈的重复模式:首先,所有的配置信息在不同的地方重复出现,其次,对于不同的配置信息进行相同的处理。

为了解决这样的重复问题,我们首先使用宏来定义“元数据”:
// Student.h

DEFINE_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.h

struct StudentOptionalConfig
{
#include 
#include "Student.h"
};
而OptionalConfig.h的定义为:
// OptionalConfigDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   OptionalConfigValue name;


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   OptionalConfigValue > name;
类似的,StudentConfig的定义则变为:
// StudentConfig.h

struct StudentConfig
{
   StudentConfig() : 
   #include 
   #include "Student.h"
   , dummy(true)
   {}

   void update(const StudentOptionalConfig& config)
   {
      #include 
      #include "Student.h"
   }

   void revert()
   {
      #include 
      #include "Student.h"
   }

   void configDone()
   {
      #include 
      #include "Student.h"
   }

private:
   #include 
   #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 name;


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   ConfigValue > name;
有了这些魔法定义文件,每个配置定义文件就呈现除了简单一致的规则,很容易就可以写出一个代码生成器,自动生成相关的代码。下面是一个Python的实现:
import sys

optional_config_template = '''
#ifndef __%s_OPTIONAL_CONFIG_H__
#define __%s_OPTIONAL_CONFIG_H__

struct %sOptionalConfig
{
   #include 
   #include "%s.h"   
};

#endif
'''


config_template = '''

#ifndef __%s_CONFIG_H__
#define __%s_CONFIG_H__

struct %sConfig
{
   %sConfig()
   #include 
   #include "%s.h"
   dummy(true)
   {}

   void update(const %sOptionalConfig& config)
   {
      #include 
      #include "%s.h"
   }

   void configDone()
   {
      #include 
      #include "%s.h"
   }

   void revert()
   {
      #include 
      #include "%s.h"
   }

private:
   #include 
   #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])

你可能感兴趣的:(设计,C++)