Any*_*orn 11 c++ java conventions
Java程序员和API似乎更喜欢显式的set/get方法.
但是我得到了C++社区对这种做法不满的印象.如果是这样,是否有一个特殊的原因(除了更多的代码行)为什么会这样?
另一方面,为什么Java社区选择使用方法而不是直接访问?
谢谢
Chu*_*dad 14
理想情况下,精心设计的类应该没有太多的获取和设置.在我看来,太多的获取和集合基本上表明其他人(可能还有许多人)需要我的数据来实现他们的目的.在那种情况下,为什么这些数据首先属于我?这违反了封装的基本原则(数据+操作在一个逻辑单元中).
因此,虽然没有技术限制和(实际上很多)'set'和'get'方法,但我会说如果你想要太多的'get'和'set',你应该暂停并重新检查你的设计.您的类接口被系统中的太多其他实体使用.
反对get/set方法的常见理由是,如果你有两个并且它们只是微不足道return x;,x = y;那么你根本没有实际封装任何东西; 您也可以将该成员公开,这样可以节省大量的样板代码.
显然有些情况下它们仍然有意义; 如果你需要在它们中做一些特殊的事情,或者你需要使用继承,特别是接口.
有一个优点是,如果您实现getter/setter,您可以在以后更改其实现,而无需更改使用它们的代码.我认为你提到的皱眉是一种YAGNI的事情,如果没有期望以这种方式改变功能,那么拥有它们几乎没有什么好处.在许多情况下,您可以稍后处理更改实现的情况.
我不知道C++社区对Java社区不屑一顾; 我的印象是,它们在Python等语言中并不常见.
我认为C++社区对getter和setter不满的原因是C++提供了更好的选择.例如:
template <class T>
class DefaultPredicate
{
public:
static bool CheckSetter (T value)
{
return true;
}
static void CheckGetter (T value)
{
}
};
template <class T, class Predicate = DefaultPredicate <T>>
class Property
{
public:
operator T ()
{
Predicate::CheckGetter (m_storage);
return m_storage;
}
Property <T, Predicate> &operator = (T rhs)
{
if (Predicate::CheckSetter (rhs))
{
m_storage = rhs;
}
return *this;
}
private:
T m_storage;
};
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用:
class Test
{
public:
Property <int> TestData;
Property <int> MoreTestData;
};
int main ()
{
Test
test;
test.TestData = 42;
test.MoreTestData = 24;
int value = test.TestData;
bool check = test.TestData == test.MoreTestData;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我在属性类中添加了一个谓词参数.有了这个,我们可以获得创造性,例如,一个属性来保存整数颜色通道值:
class NoErrorHandler
{
public:
static void SignalError (const char *const error)
{
}
};
class LogError
{
public:
static void SignalError (const char *const error)
{
std::cout << error << std::endl;
}
};
class Exception
{
public:
Exception (const char *const message) :
m_message (message)
{
}
operator const char *const ()
{
return m_message;
}
private:
const char
*const m_message;
};
class ThrowError
{
public:
static void SignalError (const char *const error)
{
throw new Exception (error);
}
};
template <class ErrorHandler = NoErrorHandler>
class RGBValuePredicate : public DefaultPredicate <int>
{
public:
static bool CheckSetter (int rhs)
{
bool
setter_ok = true;
if (rhs < 0 || rhs > 255)
{
ErrorHandler::SignalError ("RGB value out of range.");
setter_ok = false;
}
return setter_ok;
}
};
Run Code Online (Sandbox Code Playgroud)
它可以像这样使用:
class Test
{
public:
Property <int, RGBValuePredicate <> > RGBValue1;
Property <int, RGBValuePredicate <LogError> > RGBValue2;
Property <int, RGBValuePredicate <ThrowError> > RGBValue3;
};
int main ()
{
Test
test;
try
{
test.RGBValue1 = 4;
test.RGBValue2 = 5;
test.RGBValue3 = 6;
test.RGBValue1 = 400;
test.RGBValue2 = 500;
test.RGBValue3 = -6;
}
catch (Exception *error)
{
std::cout << "Exception: " << *error << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我也将错误值的处理作为模板参数.
以此为出发点,可以通过多种方式进行扩展.
例如,允许属性的存储与值的公共类型不同 - 因此上面的RGBValue可以使用unsigned char进行存储,但使用int接口.
另一个例子是更改谓词,以便它可以改变setter值.在上面的RGBValue中,这可用于将值钳位到0到255的范围,而不是生成错误.
| 归档时间: |
|
| 查看次数: |
3491 次 |
| 最近记录: |