Stop Asking for Data! Master the 'Tell, Don't Ask' Principle
Source: Dev.to
Introduction
One of the most common mistakes in Object‑Oriented Programming (OOP) is treating objects like simple data structures. We often pull data out of an object, perform some logic, and then put the result back in. This article explains the Tell, Don’t Ask (TDA) principle and shows how it improves your code using a simple Shop and Account example.
The Tell, Don’t Ask Principle
- Don’t Ask: Do not ask an object for its data to perform logic yourself.
- Tell: Tell the object what to do, and let it handle its own state.
Following TDA improves encapsulation and cohesion.
Anti‑Pattern Example
The Shop class manages logic that belongs to the Account, violating encapsulation.
package com.mateandgit.programming.chapter1_2.problem;
public class Shop {
public void sell(Account account, Product product) {
// ❌ BAD: Asking for data (getMoney)
long price = product.getPrice();
long mileage = account.getMoney();
// ❌ BAD: The Shop decides if the account has enough money
if (mileage >= price) {
// ❌ BAD: Modifying the account's state externally
account.setMoney(mileage - price);
System.out.println(product.getName() + " purchased.");
} else {
System.out.println("Insufficient balance.");
}
}
}
Problems
- Violation of Encapsulation –
Shopknows the internal details ofAccount(itsmoneyfield and how the balance is calculated). - Logic Duplication – Any other class that needs to deduct money must duplicate the
if (balance >= price)check. - Hard to Maintain – Changing validation rules (e.g., “minimum balance must remain 100”) requires updates in every class that accesses
Account.
Refactored Solution
Move the logic into the Account class. The Shop now only commands the Account.
package com.mateandgit.programming.chapter1_2.solution;
public class Shop {
public void sell(Account account, Product product) {
// ✅ GOOD: Ask a question (canAfford)
if (account.canAfford(product.getPrice())) {
// ✅ GOOD: Tell the object to do something (withdraw)
account.withdraw(product.getPrice());
System.out.println(product.getName() + " purchased.");
} else {
System.out.println("Insufficient balance.");
}
}
}
Inside the Account class you would have methods like canAfford() and withdraw() that encapsulate the logic.
Benefits of the Refactor
- Better Encapsulation –
Shopno longer knows how the withdrawal happens; it just sends a message. - Reusable Logic – Validation rules (
canAfford) are centralized inAccount. - Readability – The code reads like a sentence: “If account can afford, withdraw.”
- Higher Cohesion & Lower Coupling – Objects manage their own state, leading to cleaner, more maintainable code.
Applying Tell, Don’t Ask
- Don’t:
getSomething() → calculate → setSomething(). - Do: Create a method in the object and tell it to perform the action.
Result: high cohesion, low coupling, and better encapsulation.