C++设计中的属性处理
Attributes handling in C++ Design
这就是困扰我的地方:我有一个类的层次结构,其中包含一组属性,这些属性要么是强制性的,要么不是强制性的。这些类被序列化为 XML(或其他内容)。必需的属性应始终序列化,而那些非必需的属性应仅在我指定时才应序列化它们。
我正在寻找一种方法,可以尽可能地自动化此过程,而不必专门检查每个属性是否设置了值。
下面是一个示例:
class Book
{
QString m_author; // this is optional
QString m_secondaryAuthor; // this is optional
QString m_title; // this is mandatory
public:
QString serializePlainText()
{
QString result = "Book:";
result += m_title;
if(m_author.length()) result+= " by "+m_author;
if(m_SecondaryAuthor.length()) result+= " and "+m_SecondaryAuthor;
return result;
}
void setTitle(const QString& title)
{
m_title = title;
}
void setAuthor(const QString& author)
{
m_author = author;
}
};
当然,这只是一个简单的例子,现实生活要复杂得多,这个类可以有几百个属性。这是问题的第二部分:我需要能够以更严格的方式设置属性,即。不使用映射到字符串属性值的映射,但或多或少像上面的示例(使用 setter 函数setTitle(const QString&)
......等。。。。
考虑到以下任何奇特的方法:
- 无需手动声明和检查所有属性
- 有一个漂亮的、程序员友好的API?
我或多或少地坚持使用Qt,但这不是强制性的。
谢谢f.
如果你愿意使用预处理器为你生成代码,你可以依靠Boost.Preprocessor。例如,您可以按以下方式执行某些操作:
#define GET_TYPE( pair ) BOOST_PP_TUPLE_ELEM( 2, 0, pair )
#define GET_NAME( pair ) BOOST_PP_TUPLE_ELEM( 2, 1, pair )
#define DECLARE_MANDATORY( r, data, elem ) GET_TYPE( elem ) GET_NAME( elem );
#define DECLARE_MANDATORY_ATTRIBUTES( attributes )
BOOST_PP_SEQ_FOR_EACH( DECLARE_MANDATORY, ~, attributes )
#define DECLARE_OPTIONAL( r, data, elem ) boost::optional< GET_TYPE( elem ) > GET_NAME( elem );
#define DECLARE_OPTIONAL_ATTRIBUTES( attributes )
BOOST_PP_SEQ_FOR_EACH( DECLARE_OPTIONAL, ~, attributes )
#define MANDATORY_ACCESSORS( r, data, elem )
BOOST_PP_CAT( void set_, GET_NAME( elem ) ) (GET_TYPE( elem ) const & value) { GET_NAME( elem ) = value; }
GET_TYPE( elem ) BOOST_PP_CAT( get_, GET_NAME( elem ) ) () const { return GET_NAME( elem ); }
#define DEFINE_MANDATORY_ACCESSORS( attributes )
BOOST_PP_SEQ_FOR_EACH( MANDATORY_ACCESSORS, ~, attributes )
#define OPTIONAL_ACCESSORS( r, data, elem )
BOOST_PP_CAT( void set_, GET_NAME( elem ) ) (GET_TYPE( elem ) const & value) { GET_NAME( elem ).reset(value); }
GET_TYPE( elem ) BOOST_PP_CAT( get_, GET_NAME( elem ) ) () const { return *GET_NAME( elem ); }
#define DEFINE_OPTIONAL_ACCESSORS( attributes )
BOOST_PP_SEQ_FOR_EACH( OPTIONAL_ACCESSORS, ~, attributes )
class Book
{
#define BOOK_MANDATORY_ATTRIBUTES ((std::string, title))
#define BOOK_OPTIONAL_ATTRIBUTES ((std::string, author)) ((std::string, secondaryAuthor))
public:
DECLARE_MANDATORY_ATTRIBUTES( BOOK_MANDATORY_ATTRIBUTES )
DECLARE_OPTIONAL_ATTRIBUTES( BOOK_OPTIONAL_ATTRIBUTES )
DEFINE_MANDATORY_ACCESSORS( BOOK_MANDATORY_ATTRIBUTES )
DEFINE_OPTIONAL_ACCESSORS( BOOK_OPTIONAL_ATTRIBUTES )
};
int main()
{
Book b;
b.set_title("H2G2");
std::cout << b.get_title();
b.set_author("Douglas Adams");
std::cout << b.get_author();
}
您可以创建另一个宏来生成序列化函数的代码,利用 [ boost::optional
](http://www.boost.org/libs/optional] 来测试是否已设置可选属性。
如果不想执行代码生成,则无法自动获取属性的访问器。但是,序列化方面可以更经典地处理,例如,通过对所有属性使用公共基类。这样,您可以将它们存储在容器中,并迭代它们以要求它们自行序列化:
struct Attribute
{
virtual QString serializePlainText() = 0;
};
// Generic attribute for the most common cases
template <typename T>
class MandatoryAttribute : public Attribute
{
T value;
public:
std::string serializePlainText()
{
return boost::lexical_cast<std::string>(value);
}
};
// Generic attribute for the most common cases
template <typename T>
class OptionalAttribute : public Attribute
{
boost::optional<T> value;
public:
bool isSet() const { return value; }
std::string serializePlainText()
{
return isSet() ?
boost::lexical_cast<std::string>(value) :
"";
}
};
所以。我的第一个想法是"使用一种很好的动态语言",但我想这不是一个选择。不过,我确实有一些模糊的建议。
- 使用地图。映射可以迭代,使序列化代码的痛苦大大降低。它还使添加新属性变得更加容易。
- 使用单个 getter 和单个 setter 函数,因为这是客户端代码调用的简单最简单、最整洁的 API。
- 分别保留已知属性名称和元数据值的映射。
调用 set 时,可以在属性元数据表中查找请求的属性名称。然后,您可以执行所需的任何验证或转换。我假设您不需要对每个属性的结构提出一组独特而复杂的要求,当然......大多数属性可能只需要最小或最大长度之类的东西?
在序列化时,您可以循环访问属性元数据表,查找所有必需属性的名称,并在属性值表中查找它们。之后,遍历属性值表,并序列化任何剩余项目。
- 警告处理为错误这里有什么问题
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 处理多个异常集合的C++方法
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 使用流处理接收到的数据
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 使用QT的C 处理DOM处理后的XML属性顺序
- C++设计中的属性处理
- 从 C++ 中的 POSIX 信号处理程序获取对象属性
- 在c++中处理类的动态属性
- QML如何对属性的每次更改进行动画处理?(只有最后一个更改动画可见)
- 从属性页的事件处理程序调用DoModal()不会弹出对话框
- 如何处理矢量属性的矢量
- 移动构造函数:如何处理容器属性
- 如何获得RapidJSON模式来处理默认属性
- 有没有其他简单的方法来处理c++属性?
- 从属性表页的处理程序引发的异常
- 如何处理初始化类的大量属性