What's the advantage of using getters and setters - that only get and set - instead of simply using public fields for those variables?
使用getter和setter(只获取和设置)而不是简单地为这些变量使用公共字段有什么好处?
If getters and setters are ever doing more than just the simple get/set, I can figure this one out very quickly, but I'm not 100% clear on how:
如果getters和setters所做的不仅仅是简单的get/set,我可以很快地解决这个问题,但是我不是100%清楚如何:
public String foo;
is any worse than:
有什么比:
private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
Whereas the former takes a lot less boilerplate code.
而前者需要更少的样板代码。
38 个解决方案
#1
786
There are actually many good reasons to consider using accessors rather than directly exposing fields of a class - beyond just the argument of encapsulation and making future changes easier.
实际上,有很多很好的理由可以考虑使用访问器,而不是直接公开类的字段——除了封装和使将来的更改更容易之外。
Here are the some of the reasons I am aware of:
以下是我知道的一些原因:
- Encapsulation of behavior associated with getting or setting the property - this allows additional functionality (like validation) to be added more easily later.
- 与获取或设置属性相关的行为的封装——这允许稍后更容易地添加其他功能(如验证)。
- Hiding the internal representation of the property while exposing a property using an alternative representation.
- 隐藏属性的内部表示,同时使用替代表示公开属性。
- Insulating your public interface from change - allowing the public interface to remain constant while the implementation changes without affecting existing consumers.
- 将您的公共接口与更改隔离开来——允许公共接口保持不变,而实现更改时不会影响现有的使用者。
- Controlling the lifetime and memory management (disposal) semantics of the property - particularly important in non-managed memory environments (like C++ or Objective-C).
- 控制属性的生命周期和内存管理(处置)语义——在非托管内存环境(如c++或Objective-C)中尤为重要。
- Providing a debugging interception point for when a property changes at runtime - debugging when and where a property changed to a particular value can be quite difficult without this in some languages.
- 提供一个调试拦截点,用于在运行时进行属性更改时——在不使用某些语言的情况下,将属性更改为特定值的情况下会非常困难。
- Improved interoperability with libraries that are designed to operate against property getter/setters - Mocking, Serialization, and WPF come to mind.
- 改进了与库的互操作性,这些库设计用于对属性getter/setter进行操作——模拟、序列化和WPF。
- Allowing inheritors to change the semantics of how the property behaves and is exposed by overriding the getter/setter methods.
- 通过覆盖getter/setter方法,允许继承器更改属性的行为和公开方式的语义。
- Allowing the getter/setter to be passed around as lambda expressions rather than values.
- 允许getter/setter作为lambda表达式而不是值传递。
- Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.
- getter和setter可以允许不同的访问级别——例如,get可能是公共的,但是集合可以被保护。
#2
385
Because 2 weeks (months, years) from now when you realize that your setter needs to do more than just set the value, you'll also realize that the property has been used directly in 238 other classes :-)
因为2周(月,年)之后,当您意识到您的setter需要做的不仅仅是设置值时,您还会意识到属性已经被直接用于238个其他类:-)
#3
305
A public field is not worse than a getter/setter pair that does nothing except returning the field and assigning to it. First, it's clear that (in most languages) there is no functional difference. Any difference must be in other factors, like maintainability or readability.
公共字段并不比getter/setter对更糟糕,后者除了返回字段并为其赋值之外什么都不做。首先,很明显(在大多数语言中)没有功能差异。任何差异都必须存在于其他因素中,比如可维护性或可读性。
An oft-mentioned advantage of getter/setter pairs, isn't. There's this claim that you can change the implementation and your clients don't have to be recompiled. Supposedly, setters let you add functionality like validation later on and your clients don't even need to know about it. However, adding validation to a setter is a change to its preconditions, a violation of the previous contract, which was, quite simply, "you can put anything in here, and you can get that same thing later from the getter".
getter/setter对的一个经常提到的优点不是这样的。有一种说法是您可以更改实现,并且您的客户端不必重新编译。据说,setter允许您稍后添加验证之类的功能,而您的客户甚至不需要知道它。然而,向setter添加验证是对其先决条件的更改,违反了之前的约定,这很简单,“您可以在这里放置任何内容,您可以在稍后从getter中获得相同的内容”。
So, now that you broke the contract, changing every file in the codebase is something you should want to do, not avoid. If you avoid it you're making the assumption that all the code assumed the contract for those methods was different.
因此,既然您已经破坏了契约,那么修改代码基中的每个文件就是您应该做的事情,而不是避免。如果你避免它,你假设所有的代码都假设这些方法的契约是不同的。
If that should not have been the contract, then the interface was allowing clients to put the object in invalid states. That's the exact opposite of encapsulation If that field could not really be set to anything from the start, why wasn't the validation there from the start?
如果不应该是合同,那么接口允许客户端将对象放到无效的状态。这与封装完全相反,如果字段从一开始就不能设置为任何内容,为什么从一开始就没有验证呢?
This same argument applies to other supposed advantages of these pass-through getter/setter pairs: if you later decide to change the value being set, you're breaking the contract. If you override the default functionality in a derived class, in a way beyond a few harmless modifications (like logging or other non-observable behaviour), you're breaking the contract of the base class. That is a violation of the Liskov Substitutability Principle, which is seen as one of the tenets of OO.
同样的论点也适用于这些传递getter/setter对的其他假定优点:如果您稍后决定更改所设置的值,那么您就是违反了约定。如果您在派生类中重写默认功能,而不是进行一些无害的修改(比如日志记录或其他不可观察的行为),那么您就违反了基类的约定。这违反了Liskov可替换性原则,该原则被视为OO的原则之一。
If a class has these dumb getters and setters for every field, then it is a class that has no invariants whatsoever, no contract. Is that really object-oriented design? If all the class has is those getters and setters, it's just a dumb data holder, and dumb data holders should look like dumb data holders:
如果一个类对于每个字段都有这些哑getter和setter,那么它就是一个没有任何不变量、没有契约的类。这真的是面向对象的设计吗?如果所有的类都是getter和setter,那它就是哑数据持有者,哑数据持有者应该看起来像哑数据持有者:
class Foo {
public:
int DaysLeft;
int ContestantNumber;
};
Adding pass-through getter/setter pairs to such a class adds no value. Other classes should provide meaningful operations, not just operations that fields already provide. That's how you can define and maintain useful invariants.
向此类类添加传递getter/setter对不会增加任何值。其他类应该提供有意义的操作,而不仅仅是字段已经提供的操作。这就是如何定义和维护有用的不变量。
Client: "What can I do with an object of this class?"
Designer: "You can read and write several variables."
Client: "Oh... cool, I guess?"客户:“我可以对这个类的对象做什么?”设计者:“你可以读写多个变量。”客户:“哦……酷,我猜?”
There are reasons to use getters and setters, but if those reasons don't exist, making getter/setter pairs in the name of false encapsulation gods is not a good thing. Valid reasons to make getters or setters include the things often mentioned as the potential changes you can make later, like validation or different internal representations. Or maybe the value should be readable by clients but not writable (for example, reading the size of a dictionary), so a simple getter is a nice choice. But those reasons should be there when you make the choice, and not just as a potential thing you may want later. This is an instance of YAGNI (You Ain't Gonna Need It).
使用getter和setter是有原因的,但是如果这些原因不存在,以错误封装的名义使用getter/setter对不是一件好事。使getter或setter有效的原因包括您可以稍后进行的潜在更改,如验证或不同的内部表示。或者,值应该是可读的,而不是可写的(例如,读取字典的大小),所以简单的getter是一个不错的选择。但是当你做出选择的时候,这些原因应该是存在的,而不仅仅是你以后想要的潜在的东西。这是YAGNI的一个实例(你不需要它)。
#4
73
Lots of people talk about the advantages of getters and setters but I want to play devil's advocate. Right now I'm debugging a very large program where the programmers decided to make everything getters and setters. That might seem nice, but its a reverse-engineering nightmare.
很多人都在谈论getters和setters的优点,但是我想要扮演devil's advocate。现在我正在调试一个非常大的程序,程序员们决定做所有的getter和setter。这看起来不错,但这是逆向工程的噩梦。
Say you're looking through hundreds of lines of code and you come across this:
假设你浏览了数百行代码,你遇到了这样的情况:
person.name = "Joe";
It's a beautifully simply piece of code until you realize its a setter. Now, you follow that setter and find that it also sets person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName, and calls person.update(), which sends a query out to the database, etc. Oh, that's where your memory leak was occurring.
这是一段很简单的代码,直到你意识到它是一个setter。现在,你跟随那个setter,发现它也设置person。firstName,的人。姓,人。isHuman,的人。hasReallyCommonFirstName,并调用person.update(),它向数据库发送一个查询,等等。
Understanding a local piece of code at first glance is an important property of good readability that getters and setters tend to break. That is why I try to avoid them when I can, and minimize what they do when I use them.
乍一看,理解本地代码是一个很重要的属性,它具有良好的可读性,而getter和setter往往会中断。这就是为什么我尽量避免使用它们,并在使用它们时最小化它们的作用。
#5
44
There are many reasons. My favorite one is when you need to change the behavior or regulate what you can set on a variable. For instance, lets say you had a setSpeed(int speed) method. But you want that you can only set a maximum speed of 100. You would do something like:
有许多原因。我最喜欢的一个是当你需要改变行为或调节变量时。例如,假设您有一个setSpeed(int speed)方法。但是你想要的是你只能设置最大速度为100。你会这样做:
public void setSpeed(int speed) {
if ( speed > 100 ) {
this.speed = 100;
} else {
this.speed = speed;
}
}
Now what if EVERYWHERE in your code you were using the public field and then you realized you need the above requirement? Have fun hunting down every usage of the public field instead of just modifying your setter.
现在,如果你在代码的任何地方都使用公共字段,然后你意识到你需要上面的需求,那该怎么办呢?寻找公共字段的每个用法,而不是仅仅修改setter,这很有趣。
My 2 cents :)
我的2美分:)
#6
42
In a pure object-oriented world getters and setters is a terrible anti-pattern. Read this article: Getters/Setters. Evil. Period. In a nutshell, they encourage programmers to think about objects as of data structures, and this type of thinking is pure procedural (like in COBOL or C). In an object-oriented language there are no data structures, but only objects that expose behavior (not attributes/properties!)
在纯面向对象的世界中,getter和setter是一个糟糕的反模式。阅读本文:getter / setter。邪恶的。时期。简而言之,它们鼓励程序员将对象视为数据结构,而这种思维方式纯粹是过程性的(如COBOL或C)。
You may find more about them in Section 3.5 of Elegant Objects (my book about object-oriented programming).
您可以在优雅对象(我关于面向对象编程的书)的第3.5节中找到关于它们的更多信息。
#7
36
One advantage of accessors and mutators is that you can perform validation.
访问器和修改器的一个优点是可以执行验证。
For example, if foo
was public, I could easily set it to null
and then someone else could try to call a method on the object. But it's not there anymore! With a setFoo
method, I could ensure that foo
was never set to null
.
例如,如果foo是公共的,我可以很容易地将它设置为null,然后其他人可以尝试调用对象上的一个方法。但它再也不存在了!使用setFoo方法,我可以确保foo从未被设置为null。
Accessors and mutators also allow for encapsulation - if you aren't supposed to see the value once its set (perhaps it's set in the constructor and then used by methods, but never supposed to be changed), it will never been seen by anyone. But if you can allow other classes to see or change it, you can provide the proper accessor and/or mutator.
访问器和修改器还允许进行封装——如果您不希望在设置完值后看到它(可能是在构造函数中设置的,然后被方法使用,但不应该被修改),那么任何人都不会看到它。但是如果您允许其他类查看或更改它,您可以提供适当的访问器和/或mutator。
#8
28
Depends on your language. You've tagged this "object-oriented" rather than "Java", so I'd like to point out that ChssPly76's answer is language-dependent. In Python, for instance, there is no reason to use getters and setters. If you need to change the behavior, you can use a property, which wraps a getter and setter around basic attribute access. Something like this:
取决于你的语言。您已经标记了这个“面向对象”而不是“Java”,因此我想指出ChssPly76的答案是依赖于语言的。例如,在Python中,没有理由使用getter和setter。如果需要更改行为,可以使用属性,该属性包装了基本属性访问的getter和setter。是这样的:
class Simple(object):
def _get_value(self):
return self._value -1
def _set_value(self, new_value):
self._value = new_value + 1
def _del_value(self):
self.old_values.append(self._value)
del self._value
value = property(_get_value, _set_value, _del_value)
#9
22
Well i just want to add that even if sometimes they are necessary for the encapsulation and security of your variables/objects, if we want to code a real Object Oriented Program, then we need to STOP OVERUSING THE ACCESSORS, cause sometimes we depend a lot on them when is not really necessary and that makes almost the same as if we put the variables public.
我只是想添加,即使有时他们是必要的变量/对象的封装和安全,如果我们想要真正的面向对象的程序代码,然后我们需要停止过度使用访问器,因为有时候我们很多依赖的时候并不是必要的,使得几乎一样,如果我们把公共的变量。
#10
21
Thanks, that really clarified my thinking. Now here is (almost) 10 (almost) good reasons NOT to use getters and setters:
谢谢,这让我的思路更清晰了。现在(几乎)有10个(几乎)好的理由不使用getter和setter:
- When you realize you need to do more than just set and get the value, you can just make the field private, which will instantly tell you where you've directly accessed it.
- 当您意识到您需要做的不仅仅是设置和获取值时,您可以将字段设置为private,它将立即告诉您直接访问它的位置。
- Any validation you perform in there can only be context free, which validation rarely is in practice.
- 您在其中执行的任何验证都只能是无上下文的,这在实践中很少出现。
- You can change the value being set - this is an absolute nightmare when the caller passes you a value that they [shock horror] want you to store AS IS.
- 您可以更改正在设置的值——当调用者向您传递一个值时,这绝对是一场噩梦,因为他们(震惊地)希望您按原样存储该值。
- You can hide the internal representation - fantastic, so you're making sure that all these operations are symmetrical right?
- 你可以隐藏内部表示法——太棒了,所以你要确保所有这些操作都是对称的,对吧?
- You've insulated your public interface from changes under the sheets - if you were designing an interface and weren't sure whether direct access to something was OK, then you should have kept designing.
- 您已经将您的公共接口与表下的更改隔离开来——如果您正在设计一个接口,并且不确定是否可以直接访问某些东西,那么您应该继续设计。
- Some libraries expect this, but not many - reflection, serialization, mock objects all work just fine with public fields.
- 有些库期望如此,但不是很多——反射、序列化、模拟对象都可以在公共字段中正常工作。
- Inheriting this class, you can override default functionality - in other words you can REALLY confuse callers by not only hiding the implementation but making it inconsistent.
- 继承这个类,您可以覆盖默认的功能——换句话说,您不仅可以隐藏实现,还可以使它不一致,从而使调用者感到困惑。
The last three I'm just leaving (N/A or D/C)...
最后三个我正要离开(N/A或D/C)……
#11
21
I know it's a bit late, but I think there are some people who are interested in performance.
我知道有点晚了,但我认为有些人对表演感兴趣。
I've done a little performance test. I wrote a class "NumberHolder" which, well, holds an Integer. You can either read that Integer by using the getter method anInstance.getNumber()
or by directly accessing the number by using anInstance.number
. My programm reads the number 1,000,000,000 times, via both ways. That process is repeated five times and the time is printed. I've got the following result:
我做了一个性能测试。我写了一个类“NumberHolder”,它包含一个整数。可以通过使用getter方法anInstance.getNumber()读取该整数,也可以通过使用anInstance.number直接访问该数字。我的程序通过两种方式读取10亿次。这个过程重复五次,时间被打印出来。我得到了以下结果:
Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms
(Time 1 is the direct way, Time 2 is the getter)
(时间1是直线,时间2是getter)
You see, the getter is (almost) always a bit faster. Then I tried with different numbers of cycles. Instead of 1 million, I used 10 million and 0.1 million. The results:
你看,getter(几乎)总是快一点。然后我尝试了不同数量的循环。不是100万,而是1000万和10万。结果:
10 million cycles:
1000万个周期:
Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms
With 10 million cycles, the times are almost the same. Here are 100 thousand (0.1 million) cycles:
在1000万次循环中,时间几乎是一样的。这里有10万个(10万个)周期:
Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms
Also with different amounts of cycles, the getter is a little bit faster than the regular way. I hope this helped you.
对于不同数量的循环,getter比常规方法快一点。我希望这对你有帮助。
#12
15
Don't use getters setters unless needed for your current delivery I.e. Don't think too much about what would happen in the future, if any thing to be changed its a change request in most of the production applications, systems.
不要使用getters setters除非你需要当前的交付,也就是说,不要过多考虑将来会发生什么,如果有任何事情需要更改,在大多数生产应用程序和系统中都是一个变更请求。
Think simple, easy, add complexity when needed.
简单,简单,在需要的时候增加复杂性。
I would not take advantage of ignorance of business owners of deep technical know how just because I think it's correct or I like the approach.
我不会利用对深奥技术的企业主的无知,因为我认为它是正确的,或者我喜欢这种方法。
I have massive system written without getters setters only with access modifiers and some methods to validate n perform biz logic. If you absolutely needed the. Use anything.
我有大量没有getter的系统,只有访问修饰符和一些验证n执行biz逻辑的方法。如果你确实需要。使用任何东西。
#13
14
I spent quite a while thinking this over for the Java case, and I believe the real reasons are:
我花了很长时间来考虑Java的情况,我认为真正的原因是:
- Code to the interface, not the implementation
- 代码到接口,而不是实现
- Interfaces only specify methods, not fields
- 接口只指定方法,而不是字段
In other words, the only way you can specify a field in an interface is by providing a method for writing a new value and a method for reading the current value.
换句话说,在接口中指定字段的唯一方法是提供一个写入新值的方法和一个读取当前值的方法。
Those methods are the infamous getter and setter....
这些方法是臭名昭著的getter和setter ....
#14
14
We use getters and setters:
- for reusability
- 为可重用性
- to perform validation in later stages of programming
- 在程序设计的后期执行验证
Getter and setter methods are public interfaces to access private class members.
Getter和setter方法是访问私有类成员的公共接口。
Encapsulation mantra
The encapsulation mantra is to make fields private and methods public.
封装的口号是使字段私有和方法公有。
Getter Methods: We can get access to private variables.
Getter方法:我们可以访问私有变量。
Setter Methods: We can modify private fields.
Setter方法:我们可以修改私有字段。
Even though the getter and setter methods do not add new functionality, we can change our mind come back later to make that method
即使getter和setter方法不添加新功能,我们也可以稍后再来创建该方法
- better;
- 更好;
- safer; and
- 安全;和
- faster.
- 得更快。
Anywhere a value can be used, a method that returns that value can be added. Instead of:
任何可以使用值的地方,都可以添加返回该值的方法。而不是:
int x = 1000 - 500
use
使用
int x = 1000 - class_name.getValue();
In layman's terms
Suppose we need to store the details of this Person
. This Person
has the fields name
, age
and sex
. Doing this involves creating methods for name
, age
and sex
. Now if we need create another person, it becomes necessary to create the methods for name
, age
, sex
all over again.
假设我们需要保存这个人的细节。这个人有字段名,年龄和性别。这包括为姓名、年龄和性别创建方法。现在,如果我们需要创造另一个人,就有必要为名字、年龄、性别重新创造方法。
Instead of doing this, we can create a bean class(Person)
with getter and setter methods. So tomorrow we can just create objects of this Bean class(Person class)
whenever we need to add a new person (see the figure). Thus we are reusing the fields and methods of bean class, which is much better.
相反,我们可以使用getter和setter方法创建一个bean类(Person)。因此,明天我们只需在需要添加新Person时(参见图)创建这个Bean类(Person类)的对象。因此,我们正在重用bean类的字段和方法,这样更好。
#15
14
It can be useful for lazy-loading. Say the object in question is stored in a database, and you don't want to go get it unless you need it. If the object is retrieved by a getter, then the internal object can be null until somebody asks for it, then you can go get it on the first call to the getter.
它可以用于延迟加载。假设所讨论的对象存储在数据库中,除非需要,否则不希望获取它。如果对象是由getter获取的,那么内部对象可以为null,直到有人请求它,然后您可以在第一次调用getter时获取它。
I had a base page class in a project that was handed to me that was loading some data from a couple different web service calls, but the data in those web service calls wasn't always used in all child pages. Web services, for all of the benefits, pioneer new definitions of "slow", so you don't want to make a web service call if you don't have to.
我在一个交给我的项目中有一个基页面类,它从几个不同的web服务调用中加载一些数据,但是这些web服务调用中的数据并不总是在所有子页面中使用。尽管Web服务有很多好处,但它开创了“缓慢”的新定义,因此如果没有必要,您不希望进行Web服务调用。
I moved from public fields to getters, and now the getters check the cache, and if it's not there call the web service. So with a little wrapping, a lot of web service calls were prevented.
我从公共字段移动到getter,现在getter检查缓存,如果没有调用web服务。因此,只要稍微包装一下,就可以避免许多web服务调用。
So the getter saves me from trying to figure out, on each child page, what I will need. If I need it, I call the getter, and it goes to find it for me if I don't already have it.
所以getter避免了我试图在每个子页面上找出我需要的东西。如果我需要它,我调用getter,如果我还没有的话,它会帮我找到它。
protected YourType _yourName = null;
public YourType YourName{
get
{
if (_yourName == null)
{
_yourName = new YourType();
return _yourName;
}
}
}
#16
12
One aspect I missed in the answers so far, the access specification:
到目前为止,我在回答中漏掉了一个方面,访问规范:
- for members you have only one access specification for both setting and getting
- 对于成员,对于设置和获取,您只有一个访问规范。
- for setters and getters you can fine tune it and define it separately
- 对于setter和getter,您可以微调它并分别定义它
#17
9
In languages which don't support "properties" (C++, Java) or require recompilation of clients when changing fields to properties (C#), using get/set methods is easier to modify. For example, adding validation logic to a setFoo method will not require changing the public interface of a class.
在不支持“属性”(c++, Java)或在将字段更改为属性(c#)时需要重新编译客户机的语言中,使用get/set方法更容易修改。例如,向setFoo方法添加验证逻辑将不需要更改类的公共接口。
In languages which support "real" properties (Python, Ruby, maybe Smalltalk?) there is no point to get/set methods.
在支持“真实”属性(Python、Ruby,或者Smalltalk?)的语言中,没有必要获取/设置方法。
#18
8
EDIT: I answered this question because there are a bunch of people learning programming asking this, and most of the answers are very technically competent, but they're not as easy to understand if you're a newbie. We were all newbies, so I thought I'd try my hand at a more newbie friendly answer.
编辑:我回答了这个问题,因为有很多人在学习编程,问这个问题,而且大多数答案都很有技术能力,但是如果你是新手,就不那么容易理解了。我们都是新手,所以我想尝试用一个新手友好的回答。
The two main ones are polymorphism, and validation. Even if it's just a stupid data structure.
两种主要的方法是多态性和验证。即使它只是一个愚蠢的数据结构。
Let's say we have this simple class:
假设我们有一个简单的类:
public class Bottle {
public int amountOfWaterMl;
public int capacityMl;
}
A very simple class that holds how much liquid is in it, and what its capacity is (in milliliters).
一个非常简单的类,它包含有多少液体,它的容量是多少(单位为毫升)。
What happens when I do:
当我这样做时会发生什么:
Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacity = 1000;
Well, you wouldn't expect that to work, right? You want there to be some kind of sanity check. And worse, what if I never specified the maximum capacity? Oh dear, we have a problem.
你不会认为这行得通的,对吧?你想要一些健全的检查。更糟糕的是,如果我没有指定最大容量呢?天啊,我们有个问题。
But there's another problem too. What if bottles were just one type of container? What if we had several containers, all with capacities and amounts of liquid filled? If we could just make an interface, we could let the rest of our program accept that interface, and bottles, jerrycans and all sorts of stuff would just work interchangably. Wouldn't that be better? Since interfaces demand methods, this is also a good thing.
但还有另一个问题。如果瓶子只是一种容器呢?如果我们有几个容器,所有的容量和装满的液体?如果我们可以做一个接口,我们可以让我们的程序的其他部分接受那个接口,瓶子,jerrycans和各种各样的东西都可以相互作用。那不是更好吗?由于接口需要方法,这也是一件好事。
We'd end up with something like:
我们最终会得出这样的结论:
public interface LiquidContainer {
public int getAmountMl();
public void setAmountMl(int amountMl);
public int getCapacityMl();
public void setCapcityMl(int capacityMl);
}
Great! And now we just change Bottle to this:
太棒了!现在我们把瓶子换成这个
public class Bottle extends LiquidContainer {
private int capacityMl;
private int amountFilledMl;
public Bottle(int capacityMl, int amountFilledMl) {
this.capacityMl = capacityMl;
this.amountFilledMl = amountFilledMl;
checkNotOverFlow();
}
public int getAmountMl() {
return amountFilledMl;
}
public void setAmountMl(int amountMl) {
this.amountFilled = amountMl;
checkNotOverFlow();
}
public int getCapacityMl() {
return capacityMl;
public void setCapcityMl(int capacityMl) {
this.capacityMl = capacityMl;
checkNotOverFlow();
}
private void checkNotOverFlow() {
if(amountOfWaterMl > capacityMl) {
throw new BottleOverflowException();
}
}
I'll leave the definition ofthe BottleOverflowException as an exercise to the reader.
我将把BottleOverflowException的定义留给读者作为练习。
Now notice how much more robust this is. We can deal with any type of container in our code now by accepting LiquidContainer instead of Bottle. And how these bottles deal with this sort of stuff can all differ. You can have bottles that writer their state to disk when it changes, or bottles that save on SQL databases or GNU knows what else.
现在注意它有多健壮。我们现在可以处理我们代码中的任何类型的容器,接受液态容器而不是瓶子。这些瓶子是如何处理这些东西的,各不相同。您可以在它更改时将其状态写入到磁盘,或保存在SQL数据库或GNU上的瓶子知道其他内容。
And all these can have different ways to handle various whoopsies. The Bottle just checks and if it's overflowing it throws a RuntimeException. But that might be the wrong thing to do. (There is a useful discussion to be had about error handling, but I'm keeping it very simple here on purpose. People in comments will likely point out the flaws of this simplistic approach. ;) )
所有这些都可以有不同的方法来处理各种whoopsies。这个瓶子只是检查,如果溢出,它会抛出一个运行时异常。但这可能是错误的做法。(关于错误处理有一个很有用的讨论,但我在这里很简单地把它保持得很简单。在评论中,人们可能会指出这种简单方法的缺陷。,))
And yes, it seems like we go from a very simple idea to getting much better answers quickly.
是的,看起来我们从一个非常简单的想法快速地得到更好的答案。
There's also the third thing that not everyone has addressed: Getters and setters use method calls. That means that they look like normal methods everywhere else does. Instead of having weird specific syntax for DTOs and stuff, you have the same thing everywhere.
还有第三件事不是每个人都解决的:getter和setter使用方法调用。这意味着它们看起来像其他地方的普通方法。不同于对dto和其他东西有奇怪的特定语法,您在任何地方都有相同的东西。
#19
7
One of the basic principals of OO design: Encapsulation!
OO设计的基本原则之一:封装!
It gives you many benefits, one of which being that you can change the implementation of the getter/setter behind the scenes but any consumer of that value will continue to work as long as the data type remains the same.
它提供了许多好处,其中之一是您可以在幕后更改getter/setter的实现,但是只要数据类型不变,该值的任何使用者都将继续工作。
#20
4
From a object orientation design standpoint both alternatives can be damaging to the maintenance of the code by weakening the encapsulation of the classes. For a discussion you can look into this excellent article: http://typicalprogrammer.com/?p=23
从面向对象设计的角度来看,这两种方法都可能削弱类的封装性,从而损害代码的维护。要进行讨论,您可以查看这篇优秀的文章:http://alprogrammer.com/?
#21
4
You should use getters and setters when:
当:
- You're dealing with something that is conceptually an attribute, but:
- Your language doesn't have properties (or some similar mechanism, like Tcl's variable traces), or
- 您的语言没有属性(或者类似的机制,比如Tcl的变量跟踪),或者
- Your language's property support isn't sufficient for this use case, or
- 您的语言的属性支持对于这个用例来说是不够的
- Your language's (or sometimes your framework's) idiomatic conventions encourage getters or setters for this use case.
- 您的语言(或者有时是您的框架的)惯用惯例会鼓励getter或setter用于这个用例。
- 你处理一些概念上的属性,但是:你的语言没有属性(或一些类似的机制,比如Tcl的变量痕迹),或者你的语言的属性支持并不满足这个用例,或者你的语言(或有时你框架的)惯用惯例鼓励这个用例的getter或setter。
So this is very rarely a general OO question; it's a language-specific question, with different answers for different languages (and different use cases).
这很少是一个通用的OO问题;这是一个特定于语言的问题,对于不同的语言(以及不同的用例)有不同的答案。
From an OO theory point of view, getters and setters are useless. The interface of your class is what it does, not what its state is. (If not, you've written the wrong class.) In very simple cases, where what a class does is just, e.g., represent a point in rectangular coordinates,* the attributes are part of the interface; getters and setters just cloud that. But in anything but very simple cases, neither the attributes nor getters and setters are part of the interface.
从OO理论的角度来看,getter和setter是无用的。类的接口是它所做的,而不是它的状态。(如果没有,你写错了课。)在非常简单的情况下,类所做的只是,例如,表示矩形坐标中的一个点,*属性是接口的一部分;getters和setters只是云。但是,除了非常简单的情况外,属性、getter和setter都不是接口的一部分。
Put another way: If you believe that consumers of your class shouldn't even know that you have a spam
attribute, much less be able to change it willy-nilly, then giving them a set_spam
method is the last thing you want to do.
换句话说:如果您认为您的类的使用者甚至不应该知道您有一个垃圾邮件属性,更不要说能够随意地更改它,那么给他们一个set_spam方法是您最不想做的事情。
* Even for that simple class, you may not necessarily want to allow setting the x
and y
values. If this is really a class, shouldn't it have methods like translate
, rotate
, etc.? If it's only a class because your language doesn't have records/structs/named tuples, then this isn't really a question of OO…
*即使对于这个简单的类,也不一定要允许设置x和y值。如果这是一个类,它不应该有平移、旋转等方法吗?如果它只是一个类,因为您的语言没有记录/结构/命名元组,那么这实际上不是一个OO的问题……
But nobody is ever doing general OO design. They're doing design, and implementation, in a specific language. And in some languages, getters and setters are far from useless.
但是从来没有人做过通用的OO设计。他们用一种特定的语言进行设计和实现。在某些语言中,getter和setter绝不是无用的。
If your language doesn't have properties, then the only way to represent something that's conceptually an attribute, but is actually computed, or validated, etc., is through getters and setters.
如果您的语言没有属性,那么表示概念上是属性,但实际上是经过计算或验证的东西的唯一方法就是通过getter和setter。
Even if your language does have properties, there may be cases where they're insufficient or inappropriate. For example, if you want to allow subclasses to control the semantics of an attribute, in languages without dynamic access, a subclass can't substitute a computed property for an attribute.
即使你的语言有属性,也有可能是不够或不合适的。例如,如果您想让子类控制属性的语义,在没有动态访问的语言中,子类不能用计算属性代替属性。
As for the "what if I want to change my implementation later?" question (which is repeated multiple times in different wording in both the OP's question and the accepted answer): If it really is a pure implementation change, and you started with an attribute, you can change it to a property without affecting the interface. Unless, of course, your language doesn't support that. So this is really just the same case again.
至于“以后如果我想改变我的实现吗?”的问题(这是重复多次在不同的措辞在OP的问题和接受答案):如果它真的是一个纯粹的实现改变,你开始一个属性,您可以将它更改为一个属性不影响接口。当然,除非你的语言不支持这一点。这其实是同样的情况。
Also, it's important to follow the idioms of the language (or framework) you're using. If you write beautiful Ruby-style code in C#, any experienced C# developer other than you is going to have trouble reading it, and that's bad. Some languages have stronger cultures around their conventions than others.—and it may not be a coincidence that Java and Python, which are on opposite ends of the spectrum for how idiomatic getters are, happen to have two of the strongest cultures.
此外,遵循您使用的语言(或框架)的习惯用法也很重要。如果您在c#中编写了漂亮的ruby样式代码,那么任何有经验的c#开发人员都将难以阅读,这很糟糕。有些语言比其他语言有更强的文化。——Java和Python(它们在习惯getter的使用上处于对立的两端)碰巧拥有两种最强的文化,这也许不是巧合。
Beyond human readers, there will be libraries and tools that expect you to follow the conventions, and make your life harder if you don't. Hooking Interface Builder widgets to anything but ObjC properties, or using certain Java mocking libraries without getters, is just making your life more difficult. If the tools are important to you, don't fight them.
除了人类读者,还有一些库和工具希望你遵循这些惯例,如果你不这样做,你的生活就会变得更加困难。将接口构建器小部件连接到除ObjC属性之外的任何东西,或者使用没有getter的Java mock库,只会使您的生活更加困难。如果这些工具对你很重要,不要与它们斗争。
#22
3
Getter and setter methods are accessor methods, meaning that they are generally a public interface to change private class members. You use getter and setter methods to define a property. You access getter and setter methods as properties outside the class, even though you define them within the class as methods. Those properties outside the class can have a different name from the property name in the class.
Getter和setter方法是访问器方法,这意味着它们通常是更改私有类成员的公共接口。使用getter和setter方法来定义属性。您可以在类之外访问getter和setter方法作为属性,即使您将它们定义为方法。类之外的属性可以与类中的属性名有不同的名称。
There are some advantages to using getter and setter methods, such as the ability to let you create members with sophisticated functionality that you can access like properties. They also let you create read-only and write-only properties.
使用getter和setter方法有一些优势,比如让你创建成员等复杂的功能,您可以访问属性。他们还允许您创建只读,只写属性。
Even though getter and setter methods are useful, you should be careful not to overuse them because, among other issues, they can make code maintenance more difficult in certain situations. Also, they provide access to your class implementation, like public members. OOP practice discourages direct access to properties within a class.
尽管getter和setter方法很有用,但您应该注意不要过度使用它们,因为除了其他问题之外,它们在某些情况下会使代码维护更加困难。此外,它们还提供对类实现的访问,如公共成员。OOP实践不鼓励直接访问类中的属性。
When you write classes, you are always encouraged to make as many as possible of your instance variables private and add getter and setter methods accordingly. This is because there are several times when you may not want to let users change certain variables within your classes. For example, if you have a private static method that tracks the number of instances created for a specific class, you don't want a user to modify that counter using code. Only the constructor statement should increment that variable whenever it's called. In this situation, you might create a private instance variable and allow a getter method only for the counter variable, which means users are able to retrieve the current value only by using the getter method, and they won't be able to set new values using the setter method. Creating a getter without a setter is a simple way of making certain variables in your class read-only.
当你写类,你总是鼓励尽可能多的你的私有实例变量和添加相应的getter和setter方法。这是因为有几次当你可能不想让用户改变某些变量在类。例如,如果你有一个私人静态方法跟踪创建的实例的数量为一个特定的类,您不想让用户修改计数器使用代码。只有构造函数声明应该增加,只要它被称为变量。在这种情况下,您可以创建一个私有实例变量和计数器变量只允许一个getter方法,这意味着用户可以检索当前价值只有通过使用getter方法,他们将无法使用setter方法设置新值。创建getter没有setter是一个简单的方法让你们班上某些变量只读的。
#23
3
Code evolves. private
is great for when you need data member protection. Eventually all classes should be sort of "miniprograms" that have a well-defined interface that you can't just screw with the internals of.
代码的演化。private在需要数据成员保护时非常有用。最终,所有的类都应该是某种“小型程序”,它们具有定义良好的接口,您不能仅仅依靠内部接口。
That said, software development isn't about setting down that final version of the class as if you're pressing some cast iron statue on the first try. While you're working with it, code is more like clay. It evolves as you develop it and learn more about the problem domain you are solving. During development classes may interact with each other than they should (dependency you plan to factor out), merge together, or split apart. So I think the debate boils down to people not wanting to religiously write
也就是说,软件开发并不是要在第一次尝试的时候就把这个类的最终版本压下来。当您使用它时,代码更像粘土。它会随着你的发展而不断变化,并对你正在解决的问题领域有更多的了解。在开发过程中,类之间可能会相互影响(您计划提出的依赖关系)、合并或分离。因此,我认为这场辩论的关键在于人们不希望宗教写作。
int getVar() const { return var ; }
So you have:
所以你有:
doSomething( obj->getVar() ) ;
Instead of
而不是
doSomething( obj->var ) ;
Not only is getVar()
visually noisy, it gives this illusion that gettingVar()
is somehow a more complex process than it really is. How you (as the class writer) regard the sanctity of var
is particularly confusing to a user of your class if it has a passthru setter -- then it looks like you're putting up these gates to "protect" something you insist is valuable, (the sanctity of var
) but yet even you concede var
's protection isn't worth much by the ability for anyone to just come in and set
var
to whatever value they want, without you even peeking at what they are doing.
getVar()不仅在视觉上很吵,而且给人一种错觉,认为gettingVar()在某种程度上是一个比实际更复杂的过程。如何(如类作家)方面的神圣var尤其令人困惑的用户类,如果它有一个passthru setter,那么它看起来像你把这些门来“保护”你坚持的东西是有价值的,(var)的神圣性,但即使你承认var的保护不值得任何人来的能力和var设置为任何他们想要的价值,甚至没有你看他们在做什么。
So I program as follows (assuming an "agile" type approach -- ie when I write code not knowing exactly what it will be doing/don't have time or experience to plan an elaborate waterfall style interface set):
因此,我按照以下方式进行编程(假设采用“敏捷”类型的方法——比如,当我编写代码时,不知道它将会做什么/没有时间或经验来计划一个精心设计的瀑布式界面集):
1) Start with all public members for basic objects with data and behavior. This is why in all my C++ "example" code you'll notice me using struct
instead of class
everywhere.
1)以数据和行为为基本对象的所有公共成员开始。这就是为什么在我所有的c++“示例”代码中,您会注意到我使用了struct,而不是在任何地方都使用类。
2) When an object's internal behavior for a data member becomes complex enough, (for example, it likes to keep an internal std::list
in some kind of order), accessor type functions are written. Because I'm programming by myself, I don't always set the member private
right away, but somewhere down the evolution of the class the member will be "promoted" to either protected
or private
.
2)当对象对数据成员的内部行为变得足够复杂时(例如,它喜欢保持某种顺序的内部std::list),读写方法类型函数。因为我是自己编程的,所以我不会马上将成员设置为private,但是在类的演化过程中,成员将被“提升”为protected或private。
3) Classes that are fully fleshed out and have strict rules about their internals (ie they know exactly what they are doing, and you are not to "fuck" (technical term) with its internals) are given the class
designation, default private members, and only a select few members are allowed to be public
.
3)类完全充实和有严格的规则对他们内部(即他们确切地知道他们在做什么,你不是“他妈的”(技术术语),其内部)给出类指定,默认的私有成员,只有少数成员可以是公开的。
I find this approach allows me to avoid sitting there and religiously writing getter/setters when a lot of data members get migrated out, shifted around, etc. during the early stages of a class's evolution.
我发现这种方法可以让我避免坐在那里,并且在一个类的早期演化过程中,当大量的数据成员被迁移、转移等等时,我就会虔诚地编写getter/setters。
#24
3
There is a good reason to consider using accessors is there is no property inheritance. See next example:
有充分的理由考虑使用访问器,因为没有属性继承。看到下一个例子:
public class TestPropertyOverride {
public static class A {
public int i = 0;
public void add() {
i++;
}
public int getI() {
return i;
}
}
public static class B extends A {
public int i = 2;
@Override
public void add() {
i = i + 2;
}
@Override
public int getI() {
return i;
}
}
public static void main(String[] args) {
A a = new B();
System.out.println(a.i);
a.add();
System.out.println(a.i);
System.out.println(a.getI());
}
}
Output:
输出:
0
0
4
#25
2
One other use (in languages that support properties) is that setters and getters can imply that an operation is non-trivial. Typically, you want to avoid doing anything that's computationally expensive in a property.
另一个使用(在语言支持属性)是setter和getter可以暗示一个操作是不平凡的。通常,您希望避免做任何计算昂贵的一个属性。
#26
2
Getters and setters are used to implement two of the fundamental aspects of Object Oriented Programming which are:
getter和setter用于实现面向对象编程的两个基本方面:
- Abstraction
- 抽象
- Encapsulation
- 封装
Suppose we have an Employee class:
假设我们有一个员工类:
package com.highmark.productConfig.types;
public class Employee {
private String firstName;
private String middleName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName(){
return this.getFirstName() + this.getMiddleName() + this.getLastName();
}
}
Here the implementation details of Full Name is hidden from the user and is not accessible directly to the user, unlike a public attribute.
在这里,全名的实现细节对用户是隐藏的,与公共属性不同,用户不能直接访问它。
#27
2
One relatively modern advantage of getters/setters is that is makes it easier to browse code in tagged (indexed) code editors. E.g. If you want to see who sets a member, you can open the call hierarchy of the setter.
getter /setter的一个相对现代的优点是,它使在带标签(索引)的代码编辑器中浏览代码更加容易。如果你想知道谁设置了成员,你可以打开setter的调用层次结构。
On the other hand, if the member is public, the tools don't make it possible to filter read/write access to the member. So you have to trudge though all uses of the member.
另一方面,如果成员是公共的,这些工具不能过滤成员的读/写访问。所以你必须跋涉通过所有的使用成员。
#28
1
Additionally, this is to "future-proof" your class. In particular, changing from a field to a property is an ABI break, so if you do later decide that you need more logic than just "set/get the field", then you need to break ABI, which of course creates problems for anything else already compiled against your class.
此外,这是为了“防止未来”您的类。特别是,从字段更改为属性是一种ABI中断,因此,如果您稍后决定需要更多的逻辑,而不仅仅是“设置/获取字段”,那么您需要中断ABI,这当然会为针对您的类编译的其他任何东西带来问题。
#29
1
I would just like to throw the idea of annotation : @getter and @setter. With @getter, you should be able to obj = class.field but not class.field = obj. With @setter, vice versa. With @getter and @setter you should be able to do both. This would preserve encapsulation and reduce the time by not calling trivial methods at runtime.
我想提出注释的概念:@getter和@setter。使用@getter,您应该能够obj = class。但不是类。场= obj。@ setter,反之亦然。有了@getter和@setter,您应该可以同时做到这两点。这将保持封装性,并通过在运行时不调用普通方法来减少时间。
#30
1
I can think of one reason why you wouldn't just want everything public.
我能想到一个原因,为什么你不想让所有的东西都公开。
For instance, variable you never intended to use outside of the class could be accessed, even irdirectly via chain variable access (i.e. object.item.origin.x ).
例如,您从未打算在类之外使用的变量可以被访问,甚至可以通过链变量访问(例如object.item.origin)直接访问。x)。
By having mostly everything private, and only the stuff you want to extend and possibly refer to in subclasses as protected, and generally only having static final objects as public, then you can control what other programmers and programs can use in the API and what it can access and what it can't by using setters and getters to access the stuff you want the program, or indeed possibly other programmers who just happen to use your code, can modify in your program.
主要通过私人的一切,只有你想要的东西在子类扩展和可能指的是保护,和通常只在静态最终对象作为公众,然后你就可以控制其他程序员和程序可以使用API,它可以访问什么,它不能通过使用setter和getter访问你想要的东西,或者可能其他程序员刚刚发生在使用你的代码,可以修改你的程序。
#1
786
There are actually many good reasons to consider using accessors rather than directly exposing fields of a class - beyond just the argument of encapsulation and making future changes easier.
实际上,有很多很好的理由可以考虑使用访问器,而不是直接公开类的字段——除了封装和使将来的更改更容易之外。
Here are the some of the reasons I am aware of:
以下是我知道的一些原因:
- Encapsulation of behavior associated with getting or setting the property - this allows additional functionality (like validation) to be added more easily later.
- 与获取或设置属性相关的行为的封装——这允许稍后更容易地添加其他功能(如验证)。
- Hiding the internal representation of the property while exposing a property using an alternative representation.
- 隐藏属性的内部表示,同时使用替代表示公开属性。
- Insulating your public interface from change - allowing the public interface to remain constant while the implementation changes without affecting existing consumers.
- 将您的公共接口与更改隔离开来——允许公共接口保持不变,而实现更改时不会影响现有的使用者。
- Controlling the lifetime and memory management (disposal) semantics of the property - particularly important in non-managed memory environments (like C++ or Objective-C).
- 控制属性的生命周期和内存管理(处置)语义——在非托管内存环境(如c++或Objective-C)中尤为重要。
- Providing a debugging interception point for when a property changes at runtime - debugging when and where a property changed to a particular value can be quite difficult without this in some languages.
- 提供一个调试拦截点,用于在运行时进行属性更改时——在不使用某些语言的情况下,将属性更改为特定值的情况下会非常困难。
- Improved interoperability with libraries that are designed to operate against property getter/setters - Mocking, Serialization, and WPF come to mind.
- 改进了与库的互操作性,这些库设计用于对属性getter/setter进行操作——模拟、序列化和WPF。
- Allowing inheritors to change the semantics of how the property behaves and is exposed by overriding the getter/setter methods.
- 通过覆盖getter/setter方法,允许继承器更改属性的行为和公开方式的语义。
- Allowing the getter/setter to be passed around as lambda expressions rather than values.
- 允许getter/setter作为lambda表达式而不是值传递。
- Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.
- getter和setter可以允许不同的访问级别——例如,get可能是公共的,但是集合可以被保护。
#2
385
Because 2 weeks (months, years) from now when you realize that your setter needs to do more than just set the value, you'll also realize that the property has been used directly in 238 other classes :-)
因为2周(月,年)之后,当您意识到您的setter需要做的不仅仅是设置值时,您还会意识到属性已经被直接用于238个其他类:-)
#3
305
A public field is not worse than a getter/setter pair that does nothing except returning the field and assigning to it. First, it's clear that (in most languages) there is no functional difference. Any difference must be in other factors, like maintainability or readability.
公共字段并不比getter/setter对更糟糕,后者除了返回字段并为其赋值之外什么都不做。首先,很明显(在大多数语言中)没有功能差异。任何差异都必须存在于其他因素中,比如可维护性或可读性。
An oft-mentioned advantage of getter/setter pairs, isn't. There's this claim that you can change the implementation and your clients don't have to be recompiled. Supposedly, setters let you add functionality like validation later on and your clients don't even need to know about it. However, adding validation to a setter is a change to its preconditions, a violation of the previous contract, which was, quite simply, "you can put anything in here, and you can get that same thing later from the getter".
getter/setter对的一个经常提到的优点不是这样的。有一种说法是您可以更改实现,并且您的客户端不必重新编译。据说,setter允许您稍后添加验证之类的功能,而您的客户甚至不需要知道它。然而,向setter添加验证是对其先决条件的更改,违反了之前的约定,这很简单,“您可以在这里放置任何内容,您可以在稍后从getter中获得相同的内容”。
So, now that you broke the contract, changing every file in the codebase is something you should want to do, not avoid. If you avoid it you're making the assumption that all the code assumed the contract for those methods was different.
因此,既然您已经破坏了契约,那么修改代码基中的每个文件就是您应该做的事情,而不是避免。如果你避免它,你假设所有的代码都假设这些方法的契约是不同的。
If that should not have been the contract, then the interface was allowing clients to put the object in invalid states. That's the exact opposite of encapsulation If that field could not really be set to anything from the start, why wasn't the validation there from the start?
如果不应该是合同,那么接口允许客户端将对象放到无效的状态。这与封装完全相反,如果字段从一开始就不能设置为任何内容,为什么从一开始就没有验证呢?
This same argument applies to other supposed advantages of these pass-through getter/setter pairs: if you later decide to change the value being set, you're breaking the contract. If you override the default functionality in a derived class, in a way beyond a few harmless modifications (like logging or other non-observable behaviour), you're breaking the contract of the base class. That is a violation of the Liskov Substitutability Principle, which is seen as one of the tenets of OO.
同样的论点也适用于这些传递getter/setter对的其他假定优点:如果您稍后决定更改所设置的值,那么您就是违反了约定。如果您在派生类中重写默认功能,而不是进行一些无害的修改(比如日志记录或其他不可观察的行为),那么您就违反了基类的约定。这违反了Liskov可替换性原则,该原则被视为OO的原则之一。
If a class has these dumb getters and setters for every field, then it is a class that has no invariants whatsoever, no contract. Is that really object-oriented design? If all the class has is those getters and setters, it's just a dumb data holder, and dumb data holders should look like dumb data holders:
如果一个类对于每个字段都有这些哑getter和setter,那么它就是一个没有任何不变量、没有契约的类。这真的是面向对象的设计吗?如果所有的类都是getter和setter,那它就是哑数据持有者,哑数据持有者应该看起来像哑数据持有者:
class Foo {
public:
int DaysLeft;
int ContestantNumber;
};
Adding pass-through getter/setter pairs to such a class adds no value. Other classes should provide meaningful operations, not just operations that fields already provide. That's how you can define and maintain useful invariants.
向此类类添加传递getter/setter对不会增加任何值。其他类应该提供有意义的操作,而不仅仅是字段已经提供的操作。这就是如何定义和维护有用的不变量。
Client: "What can I do with an object of this class?"
Designer: "You can read and write several variables."
Client: "Oh... cool, I guess?"客户:“我可以对这个类的对象做什么?”设计者:“你可以读写多个变量。”客户:“哦……酷,我猜?”
There are reasons to use getters and setters, but if those reasons don't exist, making getter/setter pairs in the name of false encapsulation gods is not a good thing. Valid reasons to make getters or setters include the things often mentioned as the potential changes you can make later, like validation or different internal representations. Or maybe the value should be readable by clients but not writable (for example, reading the size of a dictionary), so a simple getter is a nice choice. But those reasons should be there when you make the choice, and not just as a potential thing you may want later. This is an instance of YAGNI (You Ain't Gonna Need It).
使用getter和setter是有原因的,但是如果这些原因不存在,以错误封装的名义使用getter/setter对不是一件好事。使getter或setter有效的原因包括您可以稍后进行的潜在更改,如验证或不同的内部表示。或者,值应该是可读的,而不是可写的(例如,读取字典的大小),所以简单的getter是一个不错的选择。但是当你做出选择的时候,这些原因应该是存在的,而不仅仅是你以后想要的潜在的东西。这是YAGNI的一个实例(你不需要它)。
#4
73
Lots of people talk about the advantages of getters and setters but I want to play devil's advocate. Right now I'm debugging a very large program where the programmers decided to make everything getters and setters. That might seem nice, but its a reverse-engineering nightmare.
很多人都在谈论getters和setters的优点,但是我想要扮演devil's advocate。现在我正在调试一个非常大的程序,程序员们决定做所有的getter和setter。这看起来不错,但这是逆向工程的噩梦。
Say you're looking through hundreds of lines of code and you come across this:
假设你浏览了数百行代码,你遇到了这样的情况:
person.name = "Joe";
It's a beautifully simply piece of code until you realize its a setter. Now, you follow that setter and find that it also sets person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName, and calls person.update(), which sends a query out to the database, etc. Oh, that's where your memory leak was occurring.
这是一段很简单的代码,直到你意识到它是一个setter。现在,你跟随那个setter,发现它也设置person。firstName,的人。姓,人。isHuman,的人。hasReallyCommonFirstName,并调用person.update(),它向数据库发送一个查询,等等。
Understanding a local piece of code at first glance is an important property of good readability that getters and setters tend to break. That is why I try to avoid them when I can, and minimize what they do when I use them.
乍一看,理解本地代码是一个很重要的属性,它具有良好的可读性,而getter和setter往往会中断。这就是为什么我尽量避免使用它们,并在使用它们时最小化它们的作用。
#5
44
There are many reasons. My favorite one is when you need to change the behavior or regulate what you can set on a variable. For instance, lets say you had a setSpeed(int speed) method. But you want that you can only set a maximum speed of 100. You would do something like:
有许多原因。我最喜欢的一个是当你需要改变行为或调节变量时。例如,假设您有一个setSpeed(int speed)方法。但是你想要的是你只能设置最大速度为100。你会这样做:
public void setSpeed(int speed) {
if ( speed > 100 ) {
this.speed = 100;
} else {
this.speed = speed;
}
}
Now what if EVERYWHERE in your code you were using the public field and then you realized you need the above requirement? Have fun hunting down every usage of the public field instead of just modifying your setter.
现在,如果你在代码的任何地方都使用公共字段,然后你意识到你需要上面的需求,那该怎么办呢?寻找公共字段的每个用法,而不是仅仅修改setter,这很有趣。
My 2 cents :)
我的2美分:)
#6
42
In a pure object-oriented world getters and setters is a terrible anti-pattern. Read this article: Getters/Setters. Evil. Period. In a nutshell, they encourage programmers to think about objects as of data structures, and this type of thinking is pure procedural (like in COBOL or C). In an object-oriented language there are no data structures, but only objects that expose behavior (not attributes/properties!)
在纯面向对象的世界中,getter和setter是一个糟糕的反模式。阅读本文:getter / setter。邪恶的。时期。简而言之,它们鼓励程序员将对象视为数据结构,而这种思维方式纯粹是过程性的(如COBOL或C)。
You may find more about them in Section 3.5 of Elegant Objects (my book about object-oriented programming).
您可以在优雅对象(我关于面向对象编程的书)的第3.5节中找到关于它们的更多信息。
#7
36
One advantage of accessors and mutators is that you can perform validation.
访问器和修改器的一个优点是可以执行验证。
For example, if foo
was public, I could easily set it to null
and then someone else could try to call a method on the object. But it's not there anymore! With a setFoo
method, I could ensure that foo
was never set to null
.
例如,如果foo是公共的,我可以很容易地将它设置为null,然后其他人可以尝试调用对象上的一个方法。但它再也不存在了!使用setFoo方法,我可以确保foo从未被设置为null。
Accessors and mutators also allow for encapsulation - if you aren't supposed to see the value once its set (perhaps it's set in the constructor and then used by methods, but never supposed to be changed), it will never been seen by anyone. But if you can allow other classes to see or change it, you can provide the proper accessor and/or mutator.
访问器和修改器还允许进行封装——如果您不希望在设置完值后看到它(可能是在构造函数中设置的,然后被方法使用,但不应该被修改),那么任何人都不会看到它。但是如果您允许其他类查看或更改它,您可以提供适当的访问器和/或mutator。
#8
28
Depends on your language. You've tagged this "object-oriented" rather than "Java", so I'd like to point out that ChssPly76's answer is language-dependent. In Python, for instance, there is no reason to use getters and setters. If you need to change the behavior, you can use a property, which wraps a getter and setter around basic attribute access. Something like this:
取决于你的语言。您已经标记了这个“面向对象”而不是“Java”,因此我想指出ChssPly76的答案是依赖于语言的。例如,在Python中,没有理由使用getter和setter。如果需要更改行为,可以使用属性,该属性包装了基本属性访问的getter和setter。是这样的:
class Simple(object):
def _get_value(self):
return self._value -1
def _set_value(self, new_value):
self._value = new_value + 1
def _del_value(self):
self.old_values.append(self._value)
del self._value
value = property(_get_value, _set_value, _del_value)
#9
22
Well i just want to add that even if sometimes they are necessary for the encapsulation and security of your variables/objects, if we want to code a real Object Oriented Program, then we need to STOP OVERUSING THE ACCESSORS, cause sometimes we depend a lot on them when is not really necessary and that makes almost the same as if we put the variables public.
我只是想添加,即使有时他们是必要的变量/对象的封装和安全,如果我们想要真正的面向对象的程序代码,然后我们需要停止过度使用访问器,因为有时候我们很多依赖的时候并不是必要的,使得几乎一样,如果我们把公共的变量。
#10
21
Thanks, that really clarified my thinking. Now here is (almost) 10 (almost) good reasons NOT to use getters and setters:
谢谢,这让我的思路更清晰了。现在(几乎)有10个(几乎)好的理由不使用getter和setter:
- When you realize you need to do more than just set and get the value, you can just make the field private, which will instantly tell you where you've directly accessed it.
- 当您意识到您需要做的不仅仅是设置和获取值时,您可以将字段设置为private,它将立即告诉您直接访问它的位置。
- Any validation you perform in there can only be context free, which validation rarely is in practice.
- 您在其中执行的任何验证都只能是无上下文的,这在实践中很少出现。
- You can change the value being set - this is an absolute nightmare when the caller passes you a value that they [shock horror] want you to store AS IS.
- 您可以更改正在设置的值——当调用者向您传递一个值时,这绝对是一场噩梦,因为他们(震惊地)希望您按原样存储该值。
- You can hide the internal representation - fantastic, so you're making sure that all these operations are symmetrical right?
- 你可以隐藏内部表示法——太棒了,所以你要确保所有这些操作都是对称的,对吧?
- You've insulated your public interface from changes under the sheets - if you were designing an interface and weren't sure whether direct access to something was OK, then you should have kept designing.
- 您已经将您的公共接口与表下的更改隔离开来——如果您正在设计一个接口,并且不确定是否可以直接访问某些东西,那么您应该继续设计。
- Some libraries expect this, but not many - reflection, serialization, mock objects all work just fine with public fields.
- 有些库期望如此,但不是很多——反射、序列化、模拟对象都可以在公共字段中正常工作。
- Inheriting this class, you can override default functionality - in other words you can REALLY confuse callers by not only hiding the implementation but making it inconsistent.
- 继承这个类,您可以覆盖默认的功能——换句话说,您不仅可以隐藏实现,还可以使它不一致,从而使调用者感到困惑。
The last three I'm just leaving (N/A or D/C)...
最后三个我正要离开(N/A或D/C)……
#11
21
I know it's a bit late, but I think there are some people who are interested in performance.
我知道有点晚了,但我认为有些人对表演感兴趣。
I've done a little performance test. I wrote a class "NumberHolder" which, well, holds an Integer. You can either read that Integer by using the getter method anInstance.getNumber()
or by directly accessing the number by using anInstance.number
. My programm reads the number 1,000,000,000 times, via both ways. That process is repeated five times and the time is printed. I've got the following result:
我做了一个性能测试。我写了一个类“NumberHolder”,它包含一个整数。可以通过使用getter方法anInstance.getNumber()读取该整数,也可以通过使用anInstance.number直接访问该数字。我的程序通过两种方式读取10亿次。这个过程重复五次,时间被打印出来。我得到了以下结果:
Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms
(Time 1 is the direct way, Time 2 is the getter)
(时间1是直线,时间2是getter)
You see, the getter is (almost) always a bit faster. Then I tried with different numbers of cycles. Instead of 1 million, I used 10 million and 0.1 million. The results:
你看,getter(几乎)总是快一点。然后我尝试了不同数量的循环。不是100万,而是1000万和10万。结果:
10 million cycles:
1000万个周期:
Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms
With 10 million cycles, the times are almost the same. Here are 100 thousand (0.1 million) cycles:
在1000万次循环中,时间几乎是一样的。这里有10万个(10万个)周期:
Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms
Also with different amounts of cycles, the getter is a little bit faster than the regular way. I hope this helped you.
对于不同数量的循环,getter比常规方法快一点。我希望这对你有帮助。
#12
15
Don't use getters setters unless needed for your current delivery I.e. Don't think too much about what would happen in the future, if any thing to be changed its a change request in most of the production applications, systems.
不要使用getters setters除非你需要当前的交付,也就是说,不要过多考虑将来会发生什么,如果有任何事情需要更改,在大多数生产应用程序和系统中都是一个变更请求。
Think simple, easy, add complexity when needed.
简单,简单,在需要的时候增加复杂性。
I would not take advantage of ignorance of business owners of deep technical know how just because I think it's correct or I like the approach.
我不会利用对深奥技术的企业主的无知,因为我认为它是正确的,或者我喜欢这种方法。
I have massive system written without getters setters only with access modifiers and some methods to validate n perform biz logic. If you absolutely needed the. Use anything.
我有大量没有getter的系统,只有访问修饰符和一些验证n执行biz逻辑的方法。如果你确实需要。使用任何东西。
#13
14
I spent quite a while thinking this over for the Java case, and I believe the real reasons are:
我花了很长时间来考虑Java的情况,我认为真正的原因是:
- Code to the interface, not the implementation
- 代码到接口,而不是实现
- Interfaces only specify methods, not fields
- 接口只指定方法,而不是字段
In other words, the only way you can specify a field in an interface is by providing a method for writing a new value and a method for reading the current value.
换句话说,在接口中指定字段的唯一方法是提供一个写入新值的方法和一个读取当前值的方法。
Those methods are the infamous getter and setter....
这些方法是臭名昭著的getter和setter ....
#14
14
We use getters and setters:
- for reusability
- 为可重用性
- to perform validation in later stages of programming
- 在程序设计的后期执行验证
Getter and setter methods are public interfaces to access private class members.
Getter和setter方法是访问私有类成员的公共接口。
Encapsulation mantra
The encapsulation mantra is to make fields private and methods public.
封装的口号是使字段私有和方法公有。
Getter Methods: We can get access to private variables.
Getter方法:我们可以访问私有变量。
Setter Methods: We can modify private fields.
Setter方法:我们可以修改私有字段。
Even though the getter and setter methods do not add new functionality, we can change our mind come back later to make that method
即使getter和setter方法不添加新功能,我们也可以稍后再来创建该方法
- better;
- 更好;
- safer; and
- 安全;和
- faster.
- 得更快。
Anywhere a value can be used, a method that returns that value can be added. Instead of:
任何可以使用值的地方,都可以添加返回该值的方法。而不是:
int x = 1000 - 500
use
使用
int x = 1000 - class_name.getValue();
In layman's terms
Suppose we need to store the details of this Person
. This Person
has the fields name
, age
and sex
. Doing this involves creating methods for name
, age
and sex
. Now if we need create another person, it becomes necessary to create the methods for name
, age
, sex
all over again.
假设我们需要保存这个人的细节。这个人有字段名,年龄和性别。这包括为姓名、年龄和性别创建方法。现在,如果我们需要创造另一个人,就有必要为名字、年龄、性别重新创造方法。
Instead of doing this, we can create a bean class(Person)
with getter and setter methods. So tomorrow we can just create objects of this Bean class(Person class)
whenever we need to add a new person (see the figure). Thus we are reusing the fields and methods of bean class, which is much better.
相反,我们可以使用getter和setter方法创建一个bean类(Person)。因此,明天我们只需在需要添加新Person时(参见图)创建这个Bean类(Person类)的对象。因此,我们正在重用bean类的字段和方法,这样更好。
#15
14
It can be useful for lazy-loading. Say the object in question is stored in a database, and you don't want to go get it unless you need it. If the object is retrieved by a getter, then the internal object can be null until somebody asks for it, then you can go get it on the first call to the getter.
它可以用于延迟加载。假设所讨论的对象存储在数据库中,除非需要,否则不希望获取它。如果对象是由getter获取的,那么内部对象可以为null,直到有人请求它,然后您可以在第一次调用getter时获取它。
I had a base page class in a project that was handed to me that was loading some data from a couple different web service calls, but the data in those web service calls wasn't always used in all child pages. Web services, for all of the benefits, pioneer new definitions of "slow", so you don't want to make a web service call if you don't have to.
我在一个交给我的项目中有一个基页面类,它从几个不同的web服务调用中加载一些数据,但是这些web服务调用中的数据并不总是在所有子页面中使用。尽管Web服务有很多好处,但它开创了“缓慢”的新定义,因此如果没有必要,您不希望进行Web服务调用。
I moved from public fields to getters, and now the getters check the cache, and if it's not there call the web service. So with a little wrapping, a lot of web service calls were prevented.
我从公共字段移动到getter,现在getter检查缓存,如果没有调用web服务。因此,只要稍微包装一下,就可以避免许多web服务调用。
So the getter saves me from trying to figure out, on each child page, what I will need. If I need it, I call the getter, and it goes to find it for me if I don't already have it.
所以getter避免了我试图在每个子页面上找出我需要的东西。如果我需要它,我调用getter,如果我还没有的话,它会帮我找到它。
protected YourType _yourName = null;
public YourType YourName{
get
{
if (_yourName == null)
{
_yourName = new YourType();
return _yourName;
}
}
}
#16
12
One aspect I missed in the answers so far, the access specification:
到目前为止,我在回答中漏掉了一个方面,访问规范:
- for members you have only one access specification for both setting and getting
- 对于成员,对于设置和获取,您只有一个访问规范。
- for setters and getters you can fine tune it and define it separately
- 对于setter和getter,您可以微调它并分别定义它
#17
9
In languages which don't support "properties" (C++, Java) or require recompilation of clients when changing fields to properties (C#), using get/set methods is easier to modify. For example, adding validation logic to a setFoo method will not require changing the public interface of a class.
在不支持“属性”(c++, Java)或在将字段更改为属性(c#)时需要重新编译客户机的语言中,使用get/set方法更容易修改。例如,向setFoo方法添加验证逻辑将不需要更改类的公共接口。
In languages which support "real" properties (Python, Ruby, maybe Smalltalk?) there is no point to get/set methods.
在支持“真实”属性(Python、Ruby,或者Smalltalk?)的语言中,没有必要获取/设置方法。
#18
8
EDIT: I answered this question because there are a bunch of people learning programming asking this, and most of the answers are very technically competent, but they're not as easy to understand if you're a newbie. We were all newbies, so I thought I'd try my hand at a more newbie friendly answer.
编辑:我回答了这个问题,因为有很多人在学习编程,问这个问题,而且大多数答案都很有技术能力,但是如果你是新手,就不那么容易理解了。我们都是新手,所以我想尝试用一个新手友好的回答。
The two main ones are polymorphism, and validation. Even if it's just a stupid data structure.
两种主要的方法是多态性和验证。即使它只是一个愚蠢的数据结构。
Let's say we have this simple class:
假设我们有一个简单的类:
public class Bottle {
public int amountOfWaterMl;
public int capacityMl;
}
A very simple class that holds how much liquid is in it, and what its capacity is (in milliliters).
一个非常简单的类,它包含有多少液体,它的容量是多少(单位为毫升)。
What happens when I do:
当我这样做时会发生什么:
Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacity = 1000;
Well, you wouldn't expect that to work, right? You want there to be some kind of sanity check. And worse, what if I never specified the maximum capacity? Oh dear, we have a problem.
你不会认为这行得通的,对吧?你想要一些健全的检查。更糟糕的是,如果我没有指定最大容量呢?天啊,我们有个问题。
But there's another problem too. What if bottles were just one type of container? What if we had several containers, all with capacities and amounts of liquid filled? If we could just make an interface, we could let the rest of our program accept that interface, and bottles, jerrycans and all sorts of stuff would just work interchangably. Wouldn't that be better? Since interfaces demand methods, this is also a good thing.
但还有另一个问题。如果瓶子只是一种容器呢?如果我们有几个容器,所有的容量和装满的液体?如果我们可以做一个接口,我们可以让我们的程序的其他部分接受那个接口,瓶子,jerrycans和各种各样的东西都可以相互作用。那不是更好吗?由于接口需要方法,这也是一件好事。
We'd end up with something like:
我们最终会得出这样的结论:
public interface LiquidContainer {
public int getAmountMl();
public void setAmountMl(int amountMl);
public int getCapacityMl();
public void setCapcityMl(int capacityMl);
}
Great! And now we just change Bottle to this:
太棒了!现在我们把瓶子换成这个
public class Bottle extends LiquidContainer {
private int capacityMl;
private int amountFilledMl;
public Bottle(int capacityMl, int amountFilledMl) {
this.capacityMl = capacityMl;
this.amountFilledMl = amountFilledMl;
checkNotOverFlow();
}
public int getAmountMl() {
return amountFilledMl;
}
public void setAmountMl(int amountMl) {
this.amountFilled = amountMl;
checkNotOverFlow();
}
public int getCapacityMl() {
return capacityMl;
public void setCapcityMl(int capacityMl) {
this.capacityMl = capacityMl;
checkNotOverFlow();
}
private void checkNotOverFlow() {
if(amountOfWaterMl > capacityMl) {
throw new BottleOverflowException();
}
}
I'll leave the definition ofthe BottleOverflowException as an exercise to the reader.
我将把BottleOverflowException的定义留给读者作为练习。
Now notice how much more robust this is. We can deal with any type of container in our code now by accepting LiquidContainer instead of Bottle. And how these bottles deal with this sort of stuff can all differ. You can have bottles that writer their state to disk when it changes, or bottles that save on SQL databases or GNU knows what else.
现在注意它有多健壮。我们现在可以处理我们代码中的任何类型的容器,接受液态容器而不是瓶子。这些瓶子是如何处理这些东西的,各不相同。您可以在它更改时将其状态写入到磁盘,或保存在SQL数据库或GNU上的瓶子知道其他内容。
And all these can have different ways to handle various whoopsies. The Bottle just checks and if it's overflowing it throws a RuntimeException. But that might be the wrong thing to do. (There is a useful discussion to be had about error handling, but I'm keeping it very simple here on purpose. People in comments will likely point out the flaws of this simplistic approach. ;) )
所有这些都可以有不同的方法来处理各种whoopsies。这个瓶子只是检查,如果溢出,它会抛出一个运行时异常。但这可能是错误的做法。(关于错误处理有一个很有用的讨论,但我在这里很简单地把它保持得很简单。在评论中,人们可能会指出这种简单方法的缺陷。,))
And yes, it seems like we go from a very simple idea to getting much better answers quickly.
是的,看起来我们从一个非常简单的想法快速地得到更好的答案。
There's also the third thing that not everyone has addressed: Getters and setters use method calls. That means that they look like normal methods everywhere else does. Instead of having weird specific syntax for DTOs and stuff, you have the same thing everywhere.
还有第三件事不是每个人都解决的:getter和setter使用方法调用。这意味着它们看起来像其他地方的普通方法。不同于对dto和其他东西有奇怪的特定语法,您在任何地方都有相同的东西。
#19
7
One of the basic principals of OO design: Encapsulation!
OO设计的基本原则之一:封装!
It gives you many benefits, one of which being that you can change the implementation of the getter/setter behind the scenes but any consumer of that value will continue to work as long as the data type remains the same.
它提供了许多好处,其中之一是您可以在幕后更改getter/setter的实现,但是只要数据类型不变,该值的任何使用者都将继续工作。
#20
4
From a object orientation design standpoint both alternatives can be damaging to the maintenance of the code by weakening the encapsulation of the classes. For a discussion you can look into this excellent article: http://typicalprogrammer.com/?p=23
从面向对象设计的角度来看,这两种方法都可能削弱类的封装性,从而损害代码的维护。要进行讨论,您可以查看这篇优秀的文章:http://alprogrammer.com/?
#21
4
You should use getters and setters when:
当:
- You're dealing with something that is conceptually an attribute, but:
- Your language doesn't have properties (or some similar mechanism, like Tcl's variable traces), or
- 您的语言没有属性(或者类似的机制,比如Tcl的变量跟踪),或者
- Your language's property support isn't sufficient for this use case, or
- 您的语言的属性支持对于这个用例来说是不够的
- Your language's (or sometimes your framework's) idiomatic conventions encourage getters or setters for this use case.
- 您的语言(或者有时是您的框架的)惯用惯例会鼓励getter或setter用于这个用例。
- 你处理一些概念上的属性,但是:你的语言没有属性(或一些类似的机制,比如Tcl的变量痕迹),或者你的语言的属性支持并不满足这个用例,或者你的语言(或有时你框架的)惯用惯例鼓励这个用例的getter或setter。
So this is very rarely a general OO question; it's a language-specific question, with different answers for different languages (and different use cases).
这很少是一个通用的OO问题;这是一个特定于语言的问题,对于不同的语言(以及不同的用例)有不同的答案。
From an OO theory point of view, getters and setters are useless. The interface of your class is what it does, not what its state is. (If not, you've written the wrong class.) In very simple cases, where what a class does is just, e.g., represent a point in rectangular coordinates,* the attributes are part of the interface; getters and setters just cloud that. But in anything but very simple cases, neither the attributes nor getters and setters are part of the interface.
从OO理论的角度来看,getter和setter是无用的。类的接口是它所做的,而不是它的状态。(如果没有,你写错了课。)在非常简单的情况下,类所做的只是,例如,表示矩形坐标中的一个点,*属性是接口的一部分;getters和setters只是云。但是,除了非常简单的情况外,属性、getter和setter都不是接口的一部分。
Put another way: If you believe that consumers of your class shouldn't even know that you have a spam
attribute, much less be able to change it willy-nilly, then giving them a set_spam
method is the last thing you want to do.
换句话说:如果您认为您的类的使用者甚至不应该知道您有一个垃圾邮件属性,更不要说能够随意地更改它,那么给他们一个set_spam方法是您最不想做的事情。
* Even for that simple class, you may not necessarily want to allow setting the x
and y
values. If this is really a class, shouldn't it have methods like translate
, rotate
, etc.? If it's only a class because your language doesn't have records/structs/named tuples, then this isn't really a question of OO…
*即使对于这个简单的类,也不一定要允许设置x和y值。如果这是一个类,它不应该有平移、旋转等方法吗?如果它只是一个类,因为您的语言没有记录/结构/命名元组,那么这实际上不是一个OO的问题……
But nobody is ever doing general OO design. They're doing design, and implementation, in a specific language. And in some languages, getters and setters are far from useless.
但是从来没有人做过通用的OO设计。他们用一种特定的语言进行设计和实现。在某些语言中,getter和setter绝不是无用的。
If your language doesn't have properties, then the only way to represent something that's conceptually an attribute, but is actually computed, or validated, etc., is through getters and setters.
如果您的语言没有属性,那么表示概念上是属性,但实际上是经过计算或验证的东西的唯一方法就是通过getter和setter。
Even if your language does have properties, there may be cases where they're insufficient or inappropriate. For example, if you want to allow subclasses to control the semantics of an attribute, in languages without dynamic access, a subclass can't substitute a computed property for an attribute.
即使你的语言有属性,也有可能是不够或不合适的。例如,如果您想让子类控制属性的语义,在没有动态访问的语言中,子类不能用计算属性代替属性。
As for the "what if I want to change my implementation later?" question (which is repeated multiple times in different wording in both the OP's question and the accepted answer): If it really is a pure implementation change, and you started with an attribute, you can change it to a property without affecting the interface. Unless, of course, your language doesn't support that. So this is really just the same case again.
至于“以后如果我想改变我的实现吗?”的问题(这是重复多次在不同的措辞在OP的问题和接受答案):如果它真的是一个纯粹的实现改变,你开始一个属性,您可以将它更改为一个属性不影响接口。当然,除非你的语言不支持这一点。这其实是同样的情况。
Also, it's important to follow the idioms of the language (or framework) you're using. If you write beautiful Ruby-style code in C#, any experienced C# developer other than you is going to have trouble reading it, and that's bad. Some languages have stronger cultures around their conventions than others.—and it may not be a coincidence that Java and Python, which are on opposite ends of the spectrum for how idiomatic getters are, happen to have two of the strongest cultures.
此外,遵循您使用的语言(或框架)的习惯用法也很重要。如果您在c#中编写了漂亮的ruby样式代码,那么任何有经验的c#开发人员都将难以阅读,这很糟糕。有些语言比其他语言有更强的文化。——Java和Python(它们在习惯getter的使用上处于对立的两端)碰巧拥有两种最强的文化,这也许不是巧合。
Beyond human readers, there will be libraries and tools that expect you to follow the conventions, and make your life harder if you don't. Hooking Interface Builder widgets to anything but ObjC properties, or using certain Java mocking libraries without getters, is just making your life more difficult. If the tools are important to you, don't fight them.
除了人类读者,还有一些库和工具希望你遵循这些惯例,如果你不这样做,你的生活就会变得更加困难。将接口构建器小部件连接到除ObjC属性之外的任何东西,或者使用没有getter的Java mock库,只会使您的生活更加困难。如果这些工具对你很重要,不要与它们斗争。
#22
3
Getter and setter methods are accessor methods, meaning that they are generally a public interface to change private class members. You use getter and setter methods to define a property. You access getter and setter methods as properties outside the class, even though you define them within the class as methods. Those properties outside the class can have a different name from the property name in the class.
Getter和setter方法是访问器方法,这意味着它们通常是更改私有类成员的公共接口。使用getter和setter方法来定义属性。您可以在类之外访问getter和setter方法作为属性,即使您将它们定义为方法。类之外的属性可以与类中的属性名有不同的名称。
There are some advantages to using getter and setter methods, such as the ability to let you create members with sophisticated functionality that you can access like properties. They also let you create read-only and write-only properties.
使用getter和setter方法有一些优势,比如让你创建成员等复杂的功能,您可以访问属性。他们还允许您创建只读,只写属性。
Even though getter and setter methods are useful, you should be careful not to overuse them because, among other issues, they can make code maintenance more difficult in certain situations. Also, they provide access to your class implementation, like public members. OOP practice discourages direct access to properties within a class.
尽管getter和setter方法很有用,但您应该注意不要过度使用它们,因为除了其他问题之外,它们在某些情况下会使代码维护更加困难。此外,它们还提供对类实现的访问,如公共成员。OOP实践不鼓励直接访问类中的属性。
When you write classes, you are always encouraged to make as many as possible of your instance variables private and add getter and setter methods accordingly. This is because there are several times when you may not want to let users change certain variables within your classes. For example, if you have a private static method that tracks the number of instances created for a specific class, you don't want a user to modify that counter using code. Only the constructor statement should increment that variable whenever it's called. In this situation, you might create a private instance variable and allow a getter method only for the counter variable, which means users are able to retrieve the current value only by using the getter method, and they won't be able to set new values using the setter method. Creating a getter without a setter is a simple way of making certain variables in your class read-only.
当你写类,你总是鼓励尽可能多的你的私有实例变量和添加相应的getter和setter方法。这是因为有几次当你可能不想让用户改变某些变量在类。例如,如果你有一个私人静态方法跟踪创建的实例的数量为一个特定的类,您不想让用户修改计数器使用代码。只有构造函数声明应该增加,只要它被称为变量。在这种情况下,您可以创建一个私有实例变量和计数器变量只允许一个getter方法,这意味着用户可以检索当前价值只有通过使用getter方法,他们将无法使用setter方法设置新值。创建getter没有setter是一个简单的方法让你们班上某些变量只读的。
#23
3
Code evolves. private
is great for when you need data member protection. Eventually all classes should be sort of "miniprograms" that have a well-defined interface that you can't just screw with the internals of.
代码的演化。private在需要数据成员保护时非常有用。最终,所有的类都应该是某种“小型程序”,它们具有定义良好的接口,您不能仅仅依靠内部接口。
That said, software development isn't about setting down that final version of the class as if you're pressing some cast iron statue on the first try. While you're working with it, code is more like clay. It evolves as you develop it and learn more about the problem domain you are solving. During development classes may interact with each other than they should (dependency you plan to factor out), merge together, or split apart. So I think the debate boils down to people not wanting to religiously write
也就是说,软件开发并不是要在第一次尝试的时候就把这个类的最终版本压下来。当您使用它时,代码更像粘土。它会随着你的发展而不断变化,并对你正在解决的问题领域有更多的了解。在开发过程中,类之间可能会相互影响(您计划提出的依赖关系)、合并或分离。因此,我认为这场辩论的关键在于人们不希望宗教写作。
int getVar() const { return var ; }
So you have:
所以你有:
doSomething( obj->getVar() ) ;
Instead of
而不是
doSomething( obj->var ) ;
Not only is getVar()
visually noisy, it gives this illusion that gettingVar()
is somehow a more complex process than it really is. How you (as the class writer) regard the sanctity of var
is particularly confusing to a user of your class if it has a passthru setter -- then it looks like you're putting up these gates to "protect" something you insist is valuable, (the sanctity of var
) but yet even you concede var
's protection isn't worth much by the ability for anyone to just come in and set
var
to whatever value they want, without you even peeking at what they are doing.
getVar()不仅在视觉上很吵,而且给人一种错觉,认为gettingVar()在某种程度上是一个比实际更复杂的过程。如何(如类作家)方面的神圣var尤其令人困惑的用户类,如果它有一个passthru setter,那么它看起来像你把这些门来“保护”你坚持的东西是有价值的,(var)的神圣性,但即使你承认var的保护不值得任何人来的能力和var设置为任何他们想要的价值,甚至没有你看他们在做什么。
So I program as follows (assuming an "agile" type approach -- ie when I write code not knowing exactly what it will be doing/don't have time or experience to plan an elaborate waterfall style interface set):
因此,我按照以下方式进行编程(假设采用“敏捷”类型的方法——比如,当我编写代码时,不知道它将会做什么/没有时间或经验来计划一个精心设计的瀑布式界面集):
1) Start with all public members for basic objects with data and behavior. This is why in all my C++ "example" code you'll notice me using struct
instead of class
everywhere.
1)以数据和行为为基本对象的所有公共成员开始。这就是为什么在我所有的c++“示例”代码中,您会注意到我使用了struct,而不是在任何地方都使用类。
2) When an object's internal behavior for a data member becomes complex enough, (for example, it likes to keep an internal std::list
in some kind of order), accessor type functions are written. Because I'm programming by myself, I don't always set the member private
right away, but somewhere down the evolution of the class the member will be "promoted" to either protected
or private
.
2)当对象对数据成员的内部行为变得足够复杂时(例如,它喜欢保持某种顺序的内部std::list),读写方法类型函数。因为我是自己编程的,所以我不会马上将成员设置为private,但是在类的演化过程中,成员将被“提升”为protected或private。
3) Classes that are fully fleshed out and have strict rules about their internals (ie they know exactly what they are doing, and you are not to "fuck" (technical term) with its internals) are given the class
designation, default private members, and only a select few members are allowed to be public
.
3)类完全充实和有严格的规则对他们内部(即他们确切地知道他们在做什么,你不是“他妈的”(技术术语),其内部)给出类指定,默认的私有成员,只有少数成员可以是公开的。
I find this approach allows me to avoid sitting there and religiously writing getter/setters when a lot of data members get migrated out, shifted around, etc. during the early stages of a class's evolution.
我发现这种方法可以让我避免坐在那里,并且在一个类的早期演化过程中,当大量的数据成员被迁移、转移等等时,我就会虔诚地编写getter/setters。
#24
3
There is a good reason to consider using accessors is there is no property inheritance. See next example:
有充分的理由考虑使用访问器,因为没有属性继承。看到下一个例子:
public class TestPropertyOverride {
public static class A {
public int i = 0;
public void add() {
i++;
}
public int getI() {
return i;
}
}
public static class B extends A {
public int i = 2;
@Override
public void add() {
i = i + 2;
}
@Override
public int getI() {
return i;
}
}
public static void main(String[] args) {
A a = new B();
System.out.println(a.i);
a.add();
System.out.println(a.i);
System.out.println(a.getI());
}
}
Output:
输出:
0
0
4
#25
2
One other use (in languages that support properties) is that setters and getters can imply that an operation is non-trivial. Typically, you want to avoid doing anything that's computationally expensive in a property.
另一个使用(在语言支持属性)是setter和getter可以暗示一个操作是不平凡的。通常,您希望避免做任何计算昂贵的一个属性。
#26
2
Getters and setters are used to implement two of the fundamental aspects of Object Oriented Programming which are:
getter和setter用于实现面向对象编程的两个基本方面:
- Abstraction
- 抽象
- Encapsulation
- 封装
Suppose we have an Employee class:
假设我们有一个员工类:
package com.highmark.productConfig.types;
public class Employee {
private String firstName;
private String middleName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName(){
return this.getFirstName() + this.getMiddleName() + this.getLastName();
}
}
Here the implementation details of Full Name is hidden from the user and is not accessible directly to the user, unlike a public attribute.
在这里,全名的实现细节对用户是隐藏的,与公共属性不同,用户不能直接访问它。
#27
2
One relatively modern advantage of getters/setters is that is makes it easier to browse code in tagged (indexed) code editors. E.g. If you want to see who sets a member, you can open the call hierarchy of the setter.
getter /setter的一个相对现代的优点是,它使在带标签(索引)的代码编辑器中浏览代码更加容易。如果你想知道谁设置了成员,你可以打开setter的调用层次结构。
On the other hand, if the member is public, the tools don't make it possible to filter read/write access to the member. So you have to trudge though all uses of the member.
另一方面,如果成员是公共的,这些工具不能过滤成员的读/写访问。所以你必须跋涉通过所有的使用成员。
#28
1
Additionally, this is to "future-proof" your class. In particular, changing from a field to a property is an ABI break, so if you do later decide that you need more logic than just "set/get the field", then you need to break ABI, which of course creates problems for anything else already compiled against your class.
此外,这是为了“防止未来”您的类。特别是,从字段更改为属性是一种ABI中断,因此,如果您稍后决定需要更多的逻辑,而不仅仅是“设置/获取字段”,那么您需要中断ABI,这当然会为针对您的类编译的其他任何东西带来问题。
#29
1
I would just like to throw the idea of annotation : @getter and @setter. With @getter, you should be able to obj = class.field but not class.field = obj. With @setter, vice versa. With @getter and @setter you should be able to do both. This would preserve encapsulation and reduce the time by not calling trivial methods at runtime.
我想提出注释的概念:@getter和@setter。使用@getter,您应该能够obj = class。但不是类。场= obj。@ setter,反之亦然。有了@getter和@setter,您应该可以同时做到这两点。这将保持封装性,并通过在运行时不调用普通方法来减少时间。
#30
1
I can think of one reason why you wouldn't just want everything public.
我能想到一个原因,为什么你不想让所有的东西都公开。
For instance, variable you never intended to use outside of the class could be accessed, even irdirectly via chain variable access (i.e. object.item.origin.x ).
例如,您从未打算在类之外使用的变量可以被访问,甚至可以通过链变量访问(例如object.item.origin)直接访问。x)。
By having mostly everything private, and only the stuff you want to extend and possibly refer to in subclasses as protected, and generally only having static final objects as public, then you can control what other programmers and programs can use in the API and what it can access and what it can't by using setters and getters to access the stuff you want the program, or indeed possibly other programmers who just happen to use your code, can modify in your program.
主要通过私人的一切,只有你想要的东西在子类扩展和可能指的是保护,和通常只在静态最终对象作为公众,然后你就可以控制其他程序员和程序可以使用API,它可以访问什么,它不能通过使用setter和getter访问你想要的东西,或者可能其他程序员刚刚发生在使用你的代码,可以修改你的程序。