Keep objects talking only to their immediate friends. Fewer train-wreck chains, more intention-revealing methods. Your code gets safer, easier to change, and simpler to test. 💡
Why care?
- 🔒 Lower coupling
- 🛠 Easier refactors
- 🧪 Cleaner tests
- 📦 Better encapsulation
❌ Smell: Train-wreck chaining
// Too much knowledge about the object graph
String city = order.getCustomer().getAddress().getCity();
shippingService.shipTo(city);✅ LoD-friendly: Tell, don’t ask
// Ask the object that knows
shippingService.shipTo(order.shippingCity());class Order { private Customer customer; public String shippingCity() { return customer.shippingCity(); } } class Customer { private Address address; public String shippingCity() { return address.getCity(); } } class Address { private final String city; public Address(String city) { this.city = city; } public String getCity() { return city; } }
❌ Smell: Deep dives in streams
boolean hasLowStock = cart.getItems().stream()
.map(Item::getProduct)
.map(Product::getStock)
.anyMatch(Stock::isLow);✅ LoD-friendly: Push logic to the owner
if (cart.hasLowStockItems()) { /* ... */ } class Cart { private List<Item> items; public boolean hasLowStockItems() { return items.stream().anyMatch(i -> i.getProduct().getStock().isLow()); } }
Quick checklist 🧾
- ▶️ Prefer order.shippingCity() over order.getCustomer().getAddress().getCity()
- 🗣️ Tell objects to do things, don’t pull their guts
- 🧩 Hide structure behind intention-revealing methods
- ✂️ If you must chain, keep it within the same object (fluent APIs are usually fine)
Go further with Java certification:
Java👇
Spring👇