Refactoring 027 โ How to Remove Getters

Unleash the behavior of the object beyond access to data
TL; DR: Remove or replace Getters in ways rich in behavior that performs operations instead of exposing the inner state.
The problems that were taken 
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-bart-xiv
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-i-xqz3evd
https://haackernoon.com/how-to-find-the-stinky-barts-of-your-code-part-xiii
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-bart-xiv
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxix
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-bart-xiv
https://haackernoon.com/how-to-find-the-stinky-barts-of-your-code-part-xiii
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-i-xqz3evd
https://haackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv
Steps 
- Determining Getters that displays the condition of the inner object
- Look for all the uses of Getter at the base of the coding
- Transfer the behavior that uses Getter in the same object
- Create restrictions that perform the processes (remove the ruler)
- Update your code to use new methods
Code 
Before 
public class Invoice {
private List items;
private Customer customer;
private LocalDate dueDate;
public Invoice(Customer customer, LocalDate dueDate) {
this.customer = customer;
this.dueDate = dueDate;
this.items = new ArrayList<>();
}
public void addItem(LineItem item) {
// This is the right way
// to manipulate the internal consistency
// adding assertions and access control if necessary
items.add(item);
}
public List getItems() {
// You are exposing your internal implementation
// In some languages, you also open a backdoor to
// manipulate your own collection unless you return
// a copy
return items;
}
public Customer getCustomer() {
// You expose your accidental implementation
return customer;
}
public LocalDate getDueDate() {
// You expose your accidental implementation
return dueDate;
}
}
Invoice invoice = new Invoice(customer, dueDate);
// Calculate the total violating encapsulation principle
double total = 0;
for (LineItem item : invoice.getItems()) {
total += item.getPrice() * item.getQuantity();
}
// Check if the invoice is overdue
boolean isOverdue = LocalDate.now().isAfter(invoice.getDueDate());
// Print the customer information
System.out.println("Customer: " + invoice.getCustomer().getName());
After 
public class Invoice {
private List items;
private Customer customer;
private LocalDate dueDate;
public Invoice(Customer customer, LocalDate dueDate) {
this.customer = customer;
this.dueDate = dueDate;
this.items = new ArrayList<>();
}
public void addItem(LineItem item) {
items.add(item);
}
// Step 3: Move behavior that uses the getter into the object
public double calculateTotal() {
// Step 4: Create intention-revealing methods
double total = 0;
for (LineItem item : items) {
total += item.price() * item.quantity();
}
return total;
}
public boolean isOverdue(date) {
// Step 4: Create intention-revealing methods
// Notice you inject the time control source
// Removing the getter and breaking the coupling
return date.isAfter(dueDate);
}
public String customerInformation() {
// Step 4: Create intention-revealing methods
// You no longer print with side effects
// And coupling to a global console
return "Customer: " + customer.name();
}
// For collections, return an unmodifiable view if needed
// Only expose internal collaborators if the name
// is an actual behavior
public List items() {
return Collections.unmodifiableList(items);
}
// Only if required by frameworks
// or telling the customer is an actual responsibility
// The caller should not assume the Invoice is actually
// holding it
public String customerName() {
return customer.name();
}
// You might not need to return the dueDate
// Challenge yourself if you essentially need to expose it
// public LocalDate dueDate() {
// return dueDate;
// }
}
// Client code (Step 5: Update client code)
Invoice invoice = new Invoice(customer, dueDate);
double total = invoice.calculateTotal();
boolean isOverdue = invoice.isOverdue(date);
System.out.println(invoice.customerInformation());
Write 
Safety 
This is generally safe to return but requires accurate implementation.
You need to make sure to determine all the uses of Getter and replace them with new behavior methods.
The biggest risks occur when Getters restore changes or groups that can be changed, as the customer symbol may adjust these organisms.
You must check that behavior has not changed through comprehensive tests before and after re -construction.
For groups, return copies or unlimited views to maintain safety during the transition. For the frameworks that require access to property, you may need to maintain simple access tools without โgetโ as well as behavior -rich methods.
As usual, you should add behavioral (not structural) coverage to your code before re -stabbing.
Why is the symbol better? 
The code, which has been re -paved better because it is committed to Tell-DONT-SS The principle, which makes your things smart instead of just anemia.
The solution focuses the logic related to the data of the object within the object itself, which reduces duplication. It hides the implementation details, which allows you to change internal representation without affecting the customer icon
This approach reduces the conjugation because customers do not need to know the internal structure of the object.
It also prevents violations of Demeter by eliminating chains of Getters.
Since the essence is not mutated, the solution allows improvement of health and enforce the workplace within the object.
How does the objection improve? 
Getters removes the objection between the code and reality by making things act more like their real world counterparts.
In the real world, things do not expose their internal condition to others to manipulate them โ they perform operations based on requests.
For example, do not ask a bank account on its balance and then calculate if the drag is possible for yourself. Instead, you ask the account, โCan I pull $ 100?โ The account applies its internal rules and gives you an answer.
You can create a more sincere representation of field concepts by modeling your objects to perform operations instead of exposing data.
This enhances individual correspondence between the real world and your calculated model, which makes your code easier and corresponds to how people think about the problem of the problem.
This approach follows the Mapper principle by ensuring that calculations reflect the entities in the real world in the structure and behavior.
restrictions 
The frameworks and libraries often expect Getter series/sequence removal.
Old code uses may be widely used it is difficult to reshape once.
The unit test may become more challenging because the inner state is less easy. Remember that you should never test special methods.
Refactor with Amnesty International 
Suggested Complex: 1. Select Getters that reveals the condition of the inner organism 2. Find all Getter uses at the base of code 3.
Level 
See also 
Credit 
A picture of Kris on Pixabay
This article is part of the re -sale chain.