使用getter和setter(只获取和设置)而不是简单地为这些变量使用公共字段有什么好处?
如果getter和setter所做的不仅仅是简单的get/set,我可以很快地解决这个问题,但我不是100%清楚如何做到:
public String foo;
比:
private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
而前者需要的样板代码要少得多。
如果您想要一个只读变量,但不想让客户端改变访问它的方式,请尝试使用这个模板类:
template<typename MemberOfWhichClass, typename primative>
class ReadOnly {
friend MemberOfWhichClass;
public:
template<typename number> inline bool operator==(const number& y) const { return x == y; }
template<typename number> inline number operator+ (const number& y) const { return x + y; }
template<typename number> inline number operator- (const number& y) const { return x - y; }
template<typename number> inline number operator* (const number& y) const { return x * y; }
template<typename number> inline number operator/ (const number& y) const { return x / y; }
template<typename number> inline number operator<<(const number& y) const { return x << y; }
template<typename number> inline number operator^(const number& y) const { return x^y; }
template<typename number> inline number operator~() const { return ~x; }
template<typename number> inline operator number() const { return x; }
protected:
template<typename number> inline number operator= (const number& y) { return x = y; }
template<typename number> inline number operator+=(const number& y) { return x += y; }
template<typename number> inline number operator-=(const number& y) { return x -= y; }
template<typename number> inline number operator*=(const number& y) { return x *= y; }
template<typename number> inline number operator/=(const number& y) { return x /= y; }
primative x;
};
示例用途:
class Foo {
public:
ReadOnly<Foo, int> cantChangeMe;
};
记住,您还需要添加按位和一元运算符!这只是为了让你开始
在以下情况下,应使用getter和setter:
您处理的是概念上属于属性的东西,但是:您的语言没有财产(或类似的机制,如Tcl的变量跟踪),或您的语言的属性支持不足以满足此用例,或者您的语言(或有时您的框架)惯用惯例鼓励此用例的getter或setter。
因此,这很少是一个通用的OO问题;这是一个特定于语言的问题,对于不同的语言(和不同的用例)有不同的答案。
从OO理论的角度来看,getter和setter是无用的。你的类的接口是它所做的,而不是它的状态。(如果不是,你写错了类。)在非常简单的情况下,类所做的只是,例如,表示直角坐标中的一个点,*属性是接口的一部分;getter和setter只是为这一点添油加醋。但在非常简单的情况下,属性、getter和setter都不是接口的一部分。
换一种说法:如果你认为你的类的消费者甚至不应该知道你有一个垃圾属性,更不用说随意更改它了,那么给他们一个set_spam方法是你最不想做的事情。
*即使对于这个简单的类,您也不一定希望设置x和y值。如果这真的是一个类,它不应该有translate、rotate等方法吗。?如果它只是一个类,因为您的语言没有记录/结构/命名元组,那么这实际上不是OO的问题…
但从来没有人做过一般的面向对象设计。他们用特定的语言进行设计和实现。在某些语言中,getter和setter远非一无是处。
如果您的语言没有财产,那么表示概念上是属性但实际上是计算或验证的东西的唯一方法是通过getter和setter。
即使你的语言确实有财产,也可能有不足或不合适的情况。例如,如果要允许子类控制属性的语义,在没有动态访问的语言中,子类不能用计算属性代替属性。
至于“如果我想稍后更改我的实现怎么办?”这个问题(在OP的问题和公认的答案中以不同的措辞重复了多次):如果它真的是一个纯实现更改,并且您从一个属性开始,您可以将其更改为一个属性而不影响接口。当然,除非你的语言不支持这一点。所以这真的又是同样的情况。
此外,遵循所使用语言(或框架)的习惯用法也很重要。如果你用C#编写了漂亮的Ruby风格的代码,那么除了你之外,任何有经验的C#开发人员都会很难读懂它,这很糟糕。有些语言的习俗文化比其他语言更为浓厚-Java和Python在习惯用法方面处于对立的两端,它们恰好拥有两种最强的文化,这可能不是巧合。
除了人类读者之外,还会有图书馆和工具要求你遵守惯例,如果你不遵守惯例,会让你的生活变得更艰难。将Interface Builder小部件挂接到ObjC财产以外的任何东西上,或者在没有getter的情况下使用某些Java模拟库,只会让您的生活更加困难。如果这些工具对你很重要,不要与它们对抗。