Suppose I have the following requirements:
- We organize books by author first name, this might change in the future.
- When ever an Author we carry at our store releases a new book, the Authors previous works are discounted at the managers discretion(i.e 10% 15%).
Storage is done in an SQLite database with the appropriate tables.
Author - AuthorID, Authorfirstname, AuthorLastname
Book - BookID, Title, Price
BookswithAuthors - BookswithAuthorsID, BookID, AuthorID
From Effective Java:
Provide programmatic access to all the information contained in the value returned by the toString()
When are Getters and Setters Justified
For my examples, I'm using immutable
classes
, so any setters
will return
a new object
reflecting the change.
public final class Author{
private final String id;
private final String firstname;
private final String lastname;
//Constructor
}
ID is simply used to avoid conflicts where two authors share the same first and last name.
Given the advice in the above link, the accepted answer states:
Having getters and setters does not in itself break encapsulation. What does break encapsulation is having a getter and a setter for every data member (every field, in java lingo).
Problem 1: With all that in mind, what if, following Effect Java's advice, I have to expose all the fields with a getter because all the fields are in the toString()
?
Given the above requirement about Book organization, I could eleminate the use of getters for the first and last name and do this:
public String printAuthorbylastname(){}
public String printAuthorbyfirstname(){}
However to store in my database, I have to call ID, first and last name individually.
To handle the rule about discounts, I can do this:
public final class Book{
private String bookID;
private final String title;
private List<Authors> authorsList;
private double price;
//Constructor
}
//return a new Book reflecting the price change.
public Book updatePrice(double price){}
In keeping with the SRP
, my Book and Author classes
shouldn't be aware of the database backend, or any elements used to display(ex. textbox
, or Jtable
). This means providing getters(to all the fields in my case) to insert it into the database or display in a GUI
.
From researching I've come to the following conclusions about what developers believe about Getters/Setters
:
- Avoid entirely
- It's okay, as long as there is a justifiable reason.
- For display purposes, its fine, don't use
getters
to gather data and perform a calculation outside of the class, when it should be done inside.
Problem 2: How do you balance the guidelines given that there vastly different?
Problem 3: Suppose you choose to avoid getters/setter
entirely, how then would you display the data about an object in a GUI? If you were to pass a component used to display to anyone of the classes, doesn't this violate SRP?
toString()
method. It says: "This removes the temptation of programmers who use your class to parse the result of toString to gain access to this information." Frankly, I don't find that statement compelling; adding getters so that programmers won't be tempted to do the wrong thing with ToString() does break encapsulation.