Defining 'Tell, Don't Ask'... Well, Almost...
The big idea is that object A tells object B what to do and object B tells C as shown in the diagram below:

...and the idea behind this is that you never interrogate the state of
an object in order to make a decision about what to do next - after all,
that’s procedural programming.
To demonstrate this, I’m going to use the proverbial shopping cart
scenario in which the user adds items to the shopping cart and then gets
hold of the items to calculate their total cost.
The item code is very straight forward and looks like this:
public class Item {
private final String code;
private final Double price;
public Item(String code, Double price) {
this.code = code;
this.price = price;
}
public String getCode() {
return code;
}
public Double getPrice() {
return price;
}
}…whilst the flawed ask don’t tell shopping cart looks like this:
public class ShoppingCart {
private final List<Item> items;
public ShoppingCart() {
items = new ArrayList<Item>();
}
public void addItem(Item item) {
items.add(item);
}
public List<Item> getAllItems() {
return Collections.unmodifiableList(items);
}
}All that’s left to do here is to calculate the total code as shown in this unit test:
public class ShoppingCartTest {
/**
* Test method for {@link tell_dont_ask.ask.ShoppingCart#getAllItems()}.
*/
@Test
public void calculateTotalCost() {
ShoppingCart instance = new ShoppingCart();
Item a = new Item("gloves", 23.43);
instance.addItem(a);
Item b = new Item("hat", 10.99);
instance.addItem(b);
Item c = new Item("scarf", 5.99);
instance.addItem(c);
double totalCost = calcTotalCost(instance);
assertEquals(40.41, totalCost, 0.0001);
}
private double calcTotalCost(ShoppingCart instance) {
List<Item> items = instance.getAllItems();
double total = 0.0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
}An that should about wrap things up, the test passes and everyone's
happy. Or are they? If you look at the code more closely you’ll see that
in order to calculate the total cost the unit test client has to ask
the shopping cart to give it a list of its items and then the unit test
iterates through them to work out the total. Even though the shopping
cart quite rightly returns an immutable list, it is still giving the
unit test client code access to its internal state, breaking the rules
of encapsulation.
So, this where Tell Don’t Ask comes to the rescue...
public class ShoppingCart {
private final List<Item> items;
public ShoppingCart() {
items = new ArrayList<Item>();
}
public void addItem(Item item) {
items.add(item);
}
public double calcTotalCost() {
double total = 0.0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
}public class ShoppingCartTest {
/**
* Test method for {@link tell_dont_ask.ask.ShoppingCart#calculateTotalCost()}.
*/
@Test
public void calculateTotalCost() {
ShoppingCart instance = new ShoppingCart();
Item a = new Item("gloves", 23.43);
instance.addItem(a);
Item b = new Item("hat", 10.99);
instance.addItem(b);
Item c = new Item("scarf", 5.99);
instance.addItem(c);
double totalCost = instance.calcTotalCost();
assertEquals(40.41, totalCost, 0.0001);
}
}
In the tell don’t ask version of this code the JUnit client code tells the shopping cart that it wants its total cost and the shopping cart calculates the value, returning it to the caller.
And that’s my tell don’t ask definition in a nutshell, but is it
the end of the story? I don’t think so, after this it all becomes more
subjective. More on that later.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Vinodh Lakshmin... replied on Wed, 2012/03/14 - 10:31am
Roger: Thank you for this. Quite simple and I agree with you. However, in this specific example, when we have to list the items in the cart, we would still need the equivalent of getAllItems(), isn't it?
Mr Tegg replied on Sun, 2012/03/18 - 5:24am
in response to:
Vinodh Lakshminarayan
Developer Dude replied on Mon, 2012/03/26 - 6:30pm
in response to:
Mr Tegg
Yes, but since ListIterator implies that the implementation uses a List, you may eventually expose the implementation anyway. Or, you could add the methods that ListIterator has to the class, but then you are basically just wrapping the calls to the iterator and adding little if any value - indeed, you are probably degrading the quality of the class.
Sure, you could return an Iterator instead, and probably should when you can.
But back to the point of the article; are you really telling the object to calculate the total, or are you asking it for the total? It is kind of a matter of semantics - it can be argued that you are asking and not telling. That said, I do agree with the sentiment - to a point - I tend to come from a bit different angle; I often prefer to have objects be value objects (i.e., mostly structs) when I may have different business logic algorithms operate on them.
I may want a total in euros instead of dollars, I may want that to include a VAT value, I may want it to exclude certain items that are not taxable from the tax subtotal, I may want to give an item a discount, or give an item to a customer for no-charge. There are any number of different paths I may want to take depending on context, and I often do not want to embed that context into the object itself.
For example, I may have a telephone number class. I don't necessarily want to tell the tel. # to dial, I may want to tell a phone to dial - after all, I don't want to embed the logic for dialing every possible phone into the telephone # class. But I do probably want the tel. # class to know how validate itself, maybe how to parse a string into itself, maybe know how to output in different formats (or not - I may want a formatter doing that - after all, we have DateFormatter for formatting dates for different locales and different formats, we don't build that into the Date class).
So, it is a matter of judgement when to tell a class something and when to ask it for something.