What is the utility and advantage of getters & setters especially when they are merely used to read and assign values to properties of an object? [closed]

softwareengineering.stackexchange https://softwareengineering.stackexchange.com/questions/416386

I’m still really new to learning to program. Just learning the syntax for a few programming languages at the moment.

The courses I viewed for C# and Java touched only very briefly on getters & setters and it still didn’t make an awful lot of sense to me. So I researched them further and found that the whole subject of getters & setters is a lot more debated than I could believe. For every argument & example both for and against getters & setters there was a counter argument, saying that it was wrong, the code was a bad example etc. and I still didn’t know who to agree with or even fully grasp the jargon behind it.

So I’m really not sure what to go for at the moment. So I’m going to post my take on what getters & setters really are given what I’ve read and if there’s anything I’ve got wrong then please tell me. Then I have a few more questions that I haven’t found any answers for anywhere.

My take on getters & setters

FOR:

  • Getters and setters are methods declared within a class and applied to fields within said class, and control what other classes can access and modify these fields.

  • They’re used on fields which need to be accessed from outside their class, but at the same time cannot let anything have access other than what needs access.

  • When programmers talk about “if you make a field public then ANYONE can have access to them” by anyone they’re not necessarily talking about hackers or the user of your finished program. They’re talking about any other programmers who are working on the same program (or yourself) creating something which accidentally creates side effects which modify that class. Then you not being able to work out what is causing that change.

  • As well as controlling access they can do other things such as validate any input to the field before it is added (Mike Dane aka Giraffeacademy has used the example several times that a movie can only have 3 age ratings, so adding into the setter a method which checks the rating of a movie before it is added is a good side effect of a setter). In the same example, it can also improve the maintainability of your program, for example if a fourth rating is added, you can modify any objects where the new rating applies to just by adding it to the setter, rather than going through each movie individually.

AGAINST

  • Many programmers nowadays are strongly against the use of getters and setters. They argue that it ruins the encapsulation of your objects and makes code noisy and unreadable. Also that they encourage programmers to think of objects as data structures.

  • I’ve seen some arguments that they are now somewhat obsolete as some programming languages such as Python, which doesn’t need to use getters & setters. Also some IDE’s make it easy to see where side effects are taking place.

  • The main argument I’ve seen against them is that they’re just poor design. Code and classes should be clean and organised in a way that fields are only accessed outside the class when it absolutely needs to be, and getters and setters should only be used as a last resort.

  • An idea I saw recently is that you should start off making every field you create private. Then find everything which needs to be accessed outside the class and if there’s no other way around it, add a getter and/or setter to it.

The final, neutral argument I’ve seen is that you shouldn’t be adding things to your code that you don’t understand or don’t know if you’re going to need or not. That I absolutely agree with. But obviously I need to know if they’re going to be useful to me or not when I actually create something.

So if I’ve got anything wrong then please let me know, and I still have a few questions:

  • What parts of your program would you actually use getters and setters on? The examples I’ve seen online use classes such as ‘Dog/Ball’ and ‘Person’ which really aren’t much use to me. I’m thinking you would use them if you had a class for ‘Accounts’ and a different class for ‘Settings’.. the settings class would need to access the Account’s user name if the username requested to change it.. right?

  • Going with that example, if getters and setters are created to prevent someone from being able to change a variable through a side effect, what kind of code could actually change a user’s name as a side effect accidentally? Surely the only kind of areas in your program that could modify an accounts username are setUsername, displayUsername and changeUsername, and nothing else would ever need to go near those variables.

  • Given the debate I’ve found surrounding getters & setters why do courses and tutorials touch so briefly on them only just teaching you the syntax for them, and not arguing the cases for and against or even providing actual real world examples? (See note before about dog/ball). Are they too biased of an opinion? Or am I just looking into one topic way too much?

As I said I’m still so new to programming, so I’m probably either too inexperienced or thinking about it way too much. I just want to be absolutely clear on what I’m adding/not adding to my programs before I release them to the world.

Any help much appreciated. Have a good day.

有帮助吗?

解决方案

I’m still really new to learning to program. Just learning the syntax for a few programming languages at the moment.

And that is actually the problem here - you approach this way too much from a syntactical point of view. What you need to learn first is solving problems with programs. When the problems get larger, the programs will get larger and require more structure. That will bring you to a point where you need

  • data structures and data abstractions

  • functional abstractions

  • functions which operate on specific data structures, so the data structures might become classes, and the functions become member functions of that classes.

At that point, you will have to learn about how to design the public API of a class to create a good abstraction, for reaching a certain goal. You will also start to learn why making members "private" by default is a really good idea. If you work in some context of a real problem, you will know the precise requirements for your classes and their API, so you can decide which parts / functions / properties can stay private, and which not.

That will be the point in time where you may notice a very frequent requirement for classes: getting external access to some state information of the object (either read access - for which a getter is fine, or also write access, for which an additional setter will be required). Such state often corresponds to the content of a private member variable. However, that is not mandatory, getters and setters can also deliver (or change) values/state which are not stored directly in a member variable, but can be derived or calculated indirectly.

So in short: you do not decide about using or not using getters and setters by a pro/con list. Getters and setters are just tools which help you to solve some problems (specifically the problems you listed in your FOR section). One decides about their usage depending on if the actual problem requires them, and if they fit well to the kind of abstraction one wants to build by a class.

其他提示

Getters and setters allow the programmer to change the implementation of a class later on more easily. If the class is used elsewhere, and if there are no getters and setters, then the programmer has to change every other class which uses it. With getters and setters, the using classes can remain unchanged.

Imagine you have a class called BankAccount with a balance and a transaction history. There is another class which retrieves BankAccount objects from the database.

You find out that your program is too slow. After some profiling, it is the transaction history which takes a long time to load, yet almost all uses of the bankAccount query the balance only. Fortunately, there is a getter.

public List<Transaction> getTransactionHistory() { 
    return transactionHistory; 
}

You can simply change this getter and the way the bank account is initially loaded.

public List<Transaction> getTransactionHistory() { 
    if (transactionHistory == null) {
        loadTransactionHistory();
    }
    return transactionHistory; 
}

People who use your class don't see a difference, except that the initial loading got much faster and the subsequent call to the getter got slower.

Or you find that saving BankAccount objects back into the database takes a lot of time, even if most of the time nothing has changed. Fortunately, there is a setter on both balance and transaction history.

public void setBalance(int balance) { 
    this.balance = balance;
}

You simply add a new field, a boolean called isDirty.

public void setBalance(int balance) { 
    this.isDirty = true;
    this.balance = balance;
}

And when it comes to persisting the object again, if !isDirty you can skip the persisting.

Getters and setters make accessing fields into their own methods. When you're in Java you have to do this up front or when you decide to do it later you change the interface. In C# they have lovely properties so your clients won't care when you decide to make your public fields private.

These let you detect when something is accessing your fields. Public fields can't do that.

This is why getters and setters exist. It's certainly not that they provide encapsulation. They don't. They just let you detect when someone is breaking your encapsulation. They don't make you object oriented. They don't enable polymorphism. But they still exist for a reason.

Use getters when you can't move the method that needs access into the class with the data. If you can you should under OO. This happens when you're up against a boundary like code you don't control. You can also use a collection in these cases but using getters provides type safety that collections don't offer. When up against the boundary problem a Data Transfer Object (DTO) full of getters is still better than a pile of public fields.

Use setters when you have to mutate the class during its lifetime. It's better to be immutable but somethings can't be. Deserializers used to require this but most no longer do. Immutable objects are great but try to get two nodes to point at each other without a setter.

Much as I hate how they break encapsulation I have to admit they sometimes have their uses. I use them in behaviorless DTOs. I keep them out of my behavior objects. I don't like hybrids that try to be both.


My take on getters & setters

FOR:

  • Getters and setters are methods declared within a class and applied to fields within said class, and control what other classes can access and modify these fields.

No, access modifiers (public, private, protected, default) do that on their own. This doesn't explain the existence of getters and setters.

  • They’re used on fields which need to be accessed from outside their class, but at the same time cannot let anything have access other than what needs access.

No, getters and setters have no idea what is accessing them. Well, unless you're peeking at the call stack with some reflection magic.

  • When programmers talk about “if you make a field public then ANYONE can have access to them” by anyone they’re not necessarily talking about hackers or the user of your finished program. They’re talking about any other programmers who are working on the same program (or yourself) creating something which accidentally creates side effects which modify that class. Then you not being able to work out what is causing that change.

This is correct. Information hiding, as this is called, isn't about security (unless someone adds some toys that make it that way). This is about protecting a chunk of code from being used any old crazy way rather than through its proper interface. That way you know what you're breaking when you change it. This is why maintaining real encapsulation is important. Access modifiers encourage that by making clear what is private and what is public. "Anyone" really just means coders working on other classes.

  • As well as controlling access they can do other things such as validate any input to the field before it is added (Mike Dane aka Giraffeacademy has used the example several times that a movie can only have 3 age ratings, so adding into the setter a method which checks the rating of a movie before it is added is a good side effect of a setter). In the same example, it can also improve the maintainability of your program, for example if a fourth rating is added, you can modify any objects where the new rating applies to just by adding it to the setter, rather than going through each movie individually.

Validation is something your constructor can do. You don't need it in setters if you don't have them. Anything that might invalidate your state should trigger validation. Limit what can invalidate you.

AGAINST

  • Many programmers nowadays are strongly against the use of getters and setters. They argue that it ruins the encapsulation of your objects and makes code noisy and unreadable. Also that they encourage programmers to think of objects as data structures.

I'm strongly against brainless use of getters and setters on every field. It ruins object orientation because there's no polymorphism. I want to tell something to do something and not have to know exactly what it is or what it will do. I want something else to worry about that. I don't get that if I poke my nose into every private thing that exists.

  • I’ve seen some arguments that they are now somewhat obsolete as some programming languages such as Python, which doesn’t need to use getters & setters. Also some IDE’s make it easy to see where side effects are taking place.

What python doesn't use is enforced access modifiers. They just mark their private fields with names that start with underscores. "We're all adults here" means you'll behave and respect that right?

  • The main argument I’ve seen against them is that they’re just poor design. Code and classes should be clean and organised in a way that fields are only accessed outside the class when it absolutely needs to be, and getters and setters should only be used as a last resort.

Properly encapsulated behavioral objects shouldn't let you know that those fields even exist. They provide an interface that you use to tell them to do things and they do it. They might use those fields to make decisions but you don't need to know that.

  • An idea I saw recently is that you should start off making every field you create private. Then find everything which needs to be accessed outside the class and if there’s no other way around it, add a getter and/or setter to it.

No. This is just pretending it's OK as long as you feel guilty about it. It's also promoting the idea that once a field is public it must stay that way. Learn to move what needs the field into the object that has it. If the field value must be sent somewhere else do the sending yourself. Don't let just anyone in here to get it.

The final, neutral argument I’ve seen is that you shouldn’t be adding things to your code that you don’t understand or don’t know if you’re going to need or not. That I absolutely agree with. But obviously I need to know if they’re going to be useful to me or not when I actually create something.

Add getters and setters to Java to keep people from directly accessing fields (thus, offer no public fields). C# has properties that makes that a non issue. But if you're trying to be object oriented try to keep people from touching your fields at all.

  • What parts of your program would you actually use getters and setters on? The examples I’ve seen online use classes such as ‘Dog/Ball’ and ‘Person’ which really aren’t much use to me. I’m thinking you would use them if you had a class for ‘Accounts’ and a different class for ‘Settings’.. the settings class would need to access the Account’s user name if the username requested to change it.. right?

Getters and setters solve problems that are difficult to realistically recreate in an example.

  • Going with that example, if getters and setters are created to prevent someone from being able to change a variable through a side effect, what kind of code could actually change a user’s name as a side effect accidentally? Surely the only kind of areas in your program that could modify an accounts username are setUsername, displayUsername and changeUsername, and nothing else would ever need to go near those variables.

Getters and setters are not created to prevent changing variables through side effects. They're created so that you can detect that variables have been changed or read.

  • Given the debate I’ve found surrounding getters & setters why do courses and tutorials touch so briefly on them only just teaching you the syntax for them, and not arguing the cases for and against or even providing actual real world examples? (See note before about dog/ball). Are they too biased of an opinion? Or am I just looking into one topic way too much?

Probably because the debate is still raging. They prefer to teach people what they can prove.

I am one of the software engineers who advocates suspicion for getters and setters, but only because of how they are used today. The reason I object is mainly that application programmers have developed the bad habit of generating getters and setters for every field without considering whether or not each getter or setter is necessary.

Furthermore, as you mentioned, the default access modifier for generated getters and setters, by default in many IDE's, is public.

Some languages do not even provide access control to fields (like Python) and in others like Java it is common to use libraries like Lombok to short-circuit type-safety and encapsulation.

In some cases, application developers literally could change many classes over to public fields, delete all the getters and setters, and have equivalent functionality to what they have today while removing hundreds of lines of potentially buggy code from their applications.

Both the existence of unnecessary getters or setters, and too-relaxed access modifiers on them, have created a significant percentage of the bugs I have seen in my seventeen-year career.

Nevertheless, as others have pointed out, getters and setters themselves are a different topic than access control and immutability, which are both more important to good application design.

A library developer will pay the most attention to getters and setters because they pay the highest price for problematic designs. In their context, even access to read-only fields must be controlled through getters because at least then they can keep one consistent library API while being able to modify the implementation underneath as necessary.

Thankfully, the good news is that most languages are evolving with new higher-level constructs that provide the ability to enforce good design for various use cases. Examples include C# properties and Scala case classes.

In short: good object-oriented design is subject to the context of many factors (application vs. library, available language features, open-source vs. private) and there is no single dogma that applies in all cases.

When you're learning a new language and you're not sure about programming style, it might be good idea to take a look at the core libraries of the language. They might not always be a perfect model, but they're most likely way better than most of the code you'll see elsewhere.

Adopting a similar programming style will be beneficial. Your code will be easy to understand for anyone who is familiar with the language. If fields are not directly exposed in core libraries, then you could avoid exposing fields too just to follow the convention. Conventions are very important.

Sticking to the style of important libraries might be beneficial even when you're experienced enough to form your own opinion and even when you'd personally prefer an alternative style. If really want to abandon conventions, you can always do it in a private hobby project.

The main difference between using setters/getters/direct access and properly encapsulated objects, is a design question not a syntactical one.

The former ones are basically a holdover from our procedural past, that we can't seem to shake. It is much easier to imagine a set of instructions on some data that the CPU has to execute. This thinking results in data structures and algorithms. Therefore those who think this way will often need access to data and usually can't imagine how else they could write a program.

Object-orientation is about decomposing a problem into individual agents (objects) that do stuff. Not just any (technical) stuff, but business stuff, something that fulfills some requirement that is important for users/business people. This is why it is hard to have examples, because the methods you put in an object are determined by your requirements, not the object itself. A Book doesn't automatically have Pages or even a title, only if there is a functionality that needs it. And this functionality needs to be in the Book, therefore there will be no need to access those from the outside.

From the above it follows, we only provide access to pure data (setter/getters/direct access) if we don't, or even can't know what the supported functionality should be. This happens on the "edges" of your code. For example you are writing an http-client, you'll (probably) have to provide the raw content to the caller, because you don't (can't) know how that will be used. Inside a software, like a web-application or similar this should never happen.

I think it is awesome that you think about these things. And remember, most resources out there still didn't quite made the leap to object-orientation, so you'll have to use your own judgement, and later, you own experience.

I think you're combining two things here, using getters/setters and making a field public. There are essentially three options here:

  • add a private field
  • add a public field
  • add a private field with getter/setter

As a general rule fields should only be public if necessary, and you shouldn't expose any implementation details that the user of the class doesn't need to know by making fields public unnecessarily. Adding a getter/setter by definition also makes a field public, and some of your arguments are really about that part. But that is also independent of using a getter/setter, you have the same issues if you just make the field public.

I'm assuming C# here as I'm not entirely sure about the details in modern Java in this regard. C# has automatically generated getters and setters, which does minimize the boilerplate you'd usually have for trivial getters and setters that simply set a private field. In this case you would generally prefer to use autogenerated getters/setters instead of a public field. It adds hardly any noise, and it gives you the option to change the implementation without changing the public interface of your class and potentially breaking code using it.

In general you need to be careful to not do anything in getters and setters that a reasonable programmer would find surprising. Validation is fine, side effects that e.g. perform IO or affect other parts of your object are probably a very bad idea.

In addition to what has been said by others, I will add that there are two broad categories of uses I see for Java classes in my applications:

  • classes that encapsulate program logic about a certain area of the program (like the objects you read about in your programming textbooks!)
  • classes that exist only to hold data about an entity in the program

The latter kind have names like Customer, or Product, or Item, are generally filled up with data by reading data out of a database and creating one instance for each row of the result, or are filled in by a user with a web form. The data, once entered, is rarely changed, and there's little to no logic within the class.

For the first type, the classes that encapsulate program logic, generally your fields should be private and you shouldn't have getters and setters for the fields, except maybe for injecting dependencies or setting configuration options. This is real object-oriented code and you should take care to design a good public API.

For the second type, these are dumb data structures and all you need to do is (1) define the fields and (2) use your IDE to automatically create getters and setters for all of them. (Typically the frameworks and libraries you employ will require getters/setters.) You will hardly ever touch these again, although occasionally it becomes handy to modify a getter or setter for example to do some string formatting or to change a data type. It is pointless to worry about applying object-oriented design principles or design patterns to these cases -- they aren't really what the philosophers of those fields considered to be "objects" anyway.

As others have pointed out, you are in places conflating access control (public, private...) with the question of whether to implement getters and setters (which, depending on the language, can themselves take access control modifiers). While these are of course related, it's important to be clear which you are focusing on at any point.

However, between the lines of that discussion there are also other, more fundamental questions that need answering:

What parts of your program would you actually use getters and setters on? The examples I’ve seen online use classes such as ‘Dog/Ball’ and ‘Person’ which really aren’t much use to me. I’m thinking you would use them if you had a class for ‘Accounts’ and a different class for ‘Settings’.. the settings class would need to access the Account’s user name if the username requested to change it.. right?

No. Not necessarily, anyway, and I would say probably not. But the question of how to update the username is one you would first want to consider as part of your overall design, and in the context of your overall data model.

For example, let's say there is a business requirement to maintain settings for our product (a website). These might be configuration settings (for administrators to set options controlling how the website behaves when users edit accounts) or they might be user settings (enabling website users to choose to view the site in a different language whenever they visit, or to choose a preferred navigation style).

And let's say there is also a business requirement for both users and administrators to edit Account records, changing such things as email address, postal address, telephone number and username. Now, it could be that in your data model, the Account field values (email address, username...) are defined as "settings" in some global repository (cue Windows Registry designers!). Quite likely though, your data model defines the Account field values not as "settings" but as properties of the Account entity. And from here, the question would not be whether to implement a getter and setter for username. The question would be, "Given that we're using object orientation here, and given the relationship between the Account entity and the entities that need to interact with it, what interface should Account expose to support these interactions? Because here's the thing: the answer might be "make username public", but actually it might be "provide an UpdateUsername method (or even an UpdateAccount method) that takes as parameters both the updated value(s) and some additional information needed any time an account is updated."

Like Dog and Ball, even Account doesn't lend itself well to examples that are universally right and wrong.

In summary, focusing on getter and setters and questioning them as you have done is valuable—as are many of the points on this subject noted in other answers. But don't just think about whether to expose a field directly or via a getter/setter; think first about whether it should even be exposed. Encapsulation is key here: which entities should be responsible for implementing the business logic, and hence which entities should have the low-level knowledge that a certain business rule is met by updating a certain field? Username is pretty clear but in other cases the meaning of a field can be less clear, or may be subject to subtle or complex business logic. The caller's view should be abstracted to a higher level that doesn't assume knowledge of the low-level implementation details. In such cases, exposing a field—whichever way you do it—is not sufficient.

You mentioned the thing about making fields public then anyone can mess with your data -- that's true, but the missing thing is that a lot of times you don't want a setter, just a getter, and in some languages (like Java) there's not good ways to make fields public and immutable.

public class Foo {

  public int a; // Anyone can see this, but they can also *change* it.

  public final int b; // They can't edit this since it's final!

  public final List<Integer> intList; // Even though this is final it is still mutable.

  // But using a getter we can return a read-only copy of the list to accomplish this.
  public List<Integer> getIntList() {
    return Collections.unmodifiableList(intList);
  }
}

Often times we think of getters and setters as simply returning the value as-is or setting the value as-is, and in many cases that's all it is. Sometimes you need more fine grained control though.

Also it helps to let you change your implementation details. Say you have a method that returns the date as "YYYY-MM-DD".

public class Bar {
  public String year;
  public String month;
  public String day;

  public String getDateString() {
    return year + "-" + month + "-" + day;
  }
}

But then you find out about LocalDate class and thing it's a much simpler way to store it so you change your class to this.

public class Bar {
  public LocalDate date;

  public String getYear() {
    return getDateString().substring(0, 4);
  }

  public String getMonth() {
    return getDateString().substring(5, 7);
  }

  public String getDay() {
    return getDateString().substring(8, 10);
  }

  public String getDateString() {
    return date.toString();
  }
}

This design is cleaner, and let's hypothetically say there's more methods that makes it even more useful for whatever reason. But oh no, you make this change and push the code and now one of your teammates is complaining about a compilation error. You had the fields as public before. Their code relied on it. Now you have to argue about if you need to keep the fields or if they have to change their code. But if you had not exposed the implementation details you would not need to worry. Everything that is public is essentially like a contract about how your code will work.

I still don’t fully understand getters & setters I’m still really new to learning to program. Just learning the syntax for a few programming languages at the moment.

Getters/setters/fields/function are all implementation details around getting and changing state. Unless you are designing or working on a public api, I would recommend that you simply follow the practice of whatever project you are working on or the guidance of teacher/co-workers.

Part of the reasons to use them or not are implementation details of the language, tools and libraries of the project. If you need to deserialize a string to a class and the deserialization library only uses properties, well, the class needs to have properties.

So, there’s no one size fits all answer, and you don’t have a strong opinion, use what those around you are using, and be willing to do so on whatever project you are working on, until you do develop a strong opinion.

In C#/WPF, if you want to use data binding, you have to use properties. It doesn't work with fields.

许可以下: CC-BY-SA归因
scroll top