c++ - "Value Validation in Getter/Setter"是好的样式吗?

标签 c++ exception setter getter

我的 Getter/Setter 方法会在设置/返回值之前检查该值。当值无效时,它们会抛出异常(BadArgumentException 或 IllegalStateException)。这是必需的,因为我们使用无效值初始化所有成员 - 因此我们避免使用这些无效值(== 在其他地方出现错误/段错误/异常)。

好处是:

  • 当您从模型中收到成员值时,您就知道它们是有效的
  • 有效性检查仅在模型对象中执行
  • 取值范围在模型对象中定义

这似乎很不寻常,因为大多数新团队成员首先提示它 - 即使在我向他们解释后他们同意我的看法。

问题:这是一种好的编程风格吗? (虽然浪费了一点性能)

示例代码:

inline bool MyClass::HasGroupID const { return m_iGroupID != 0; }

int MyClass::GetGroupID() const
{
    if( !HasGroupID() )
        throw EPTIllegalStateException( "Cannot access uninitialized group ID!" );

    return m_iGroupID;

}   // END GetGroupID() const

void MyClass::SetGroupID( int iGroupID )
{
    // negative IDs are allowed!
    if( iGroupID != 0 )
        throw EPTBadArgumentException( "GroupID must not be zero!", iGroupID );

    m_iGroupID = iGroupID;

}   // END SetGroupID( int )

用法:

// in serialization
if( myObject.HasGroupID() )
    rStream.writeAttribute( "groupid", GetGroupID() );

// in de-serialization
try {
    // required attribute - throw exception if value is invalid
    myObject.SetGroupID( rStream.GetIntegerAttribute( "groupid" );
} catch( EPTBadArgumentException& rException )
{
    throw EPTBadXmlAttribute( fileName, rException );
}

最佳答案

我认为这是常见的风格,而且它肯定是第一个想法中 getter/setter 的核心动机之一。但是,在您的特定示例中,我认为它们没有意义,而且我认为通常有更好的选择:

如果在 HasGroupID 返回 false 时调用 GetGroupID 引发异常,那么这是一个程序员错误 - 因此您可能应该使用 assert。事实上,为什么一开始就有可能没有组 ID 的对象呢?这听起来像是一个有点不雅的设计。

此外,如果只有非零 ID 有效,那么您应该尝试使用专用类型更早地实现此限制。这样,所有处理组 ID 的代码都可以确保 ID 有效(事实上,编译器会强制执行此操作!)并且您不可能忘记在某个地方进行检查。考虑:

class GroupID {
public:
    explicit GroupID( int id ) : m_id( id ) {
        if ( m_id == 0 ) {
            throw EPTBadArgumentException( "GroupID must not be zero!", m_id );
        }
    }

    // You may want to allow implicit conversion or rather use an explicit getter
    operator int() const { return m_id; }
};

使用这个,你可以写

void MyClass::SetGroupID( GroupID id )
{
    // No error checking needed; we *know* it's valid, because it's a GroupID!
    // We can also use a less verbose variable name without losing readability
    // because the type name reveals the semantics.
    m_iGroupID = id;

} // END SetGroupID( int )

事实上,由于组 ID 现在是一种专用类型,您可以将函数重命名为 Set 并使用重载。所以你有 MyClass::Set(UserID)MyClass::Set(GroupID) 等等。

关于c++ - "Value Validation in Getter/Setter"是好的样式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8179239/

相关文章:

java使用getter和setter方法并返回0

java - 使用反射将值设置到对象中

c++ - 我如何解决链接错误 My visual C++ 2008 with OpenCV?

c++ - Boost 智能指针 : Can I express it in a more concise way?

java - 从 c++ 库中获取一个字符串,周围有一个 java 包装器

Java:使用 Try/Catch Exception 检查用户输入是否为 Double

c++ - 我可以在这个类中用嵌套类填充模板参数吗?

java - 我正在尝试使用 Mockito 2 模拟最终的 java 类,类被模拟,但我仍然收到未完成的 stub 异常

go - 如何编写 “exception oriented”代码而不是 “if-error oriented”代码?

javascript - 将 Javascript getter/setter 复制到另一个原型(prototype)对象