http://letstalkaboutjava.blogspot.com/2015/10/wheres-law.html
If you would like to describe Law of Demeter in one sentence, it would go like that: “talk only with your (closest) friends”.
In full form it tells that a method of particular object can call only methods that belong to:
Which means that instead of::
We should write something like this:
We are not pulling out data from the object. We are not letting them be known to the outside world. We are not working on them directly. Instead, we are telling the object what have to be done and we are waiting for the result.
After all, shouldn't it be an object’s responsibility to operate with its own attributes?
Yet, you cannot be too eager. Encapsulation is important, but it is as well important for an object to have appropriate API. API which allows for comfortable work.
And what in a situation where a particular operation requires data from a few different objects of different type?
Let’s even simplify the problem! Let’s talk about calculations that need data from different objects of the same class. Simple example can be calculation of average age in group of people, where each person is separate object.
How should we do it?
Should we ask for the age:
Or maybe we should start to think how to solve this by telling objects what we want?
We always should keep in mind encapsulation and think at least twice before we would pull out data from the object to the outer world. However, I hope that this article showed you that sometimes it is necessary.
http://martinfowler.com/bliki/TellDontAsk.html
https://robots.thoughtbot.com/tell-dont-ask
Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.
That is, you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do.
Law of Demeter - keep communication to a minimum, don't expose data you don't have to, and keep all logic within the class if possible.
Program to an interface and not an implementation.
If you would like to describe Law of Demeter in one sentence, it would go like that: “talk only with your (closest) friends”.
In full form it tells that a method of particular object can call only methods that belong to:
- the same object,
- any object that is an attribute of this object,
- any object that was passed as a method’s parameter
- any object that was locally created.
ask for the result, not for data
In short summary, the TDA principle tells us that instead of asking objects for data we should tell them what the should do and then wait for the result of the operation.Which means that instead of::
1
2
3
4
| Age age = sebastian.getAge(); if (age >= 18 ) { letDoTheThingsThatAdultsDoes(sebastian); } |
We should write something like this:
1
2
3
| if (sebastian.isAdult()) { letDoTheThingsThatAdultsDoes(sebastian); } |
the more you tell, the bigger objects can become...
The example above very well presents what the TDA principle is suppose to protect. I’m talking about encapsulation.We are not pulling out data from the object. We are not letting them be known to the outside world. We are not working on them directly. Instead, we are telling the object what have to be done and we are waiting for the result.
After all, shouldn't it be an object’s responsibility to operate with its own attributes?
Yet, you cannot be too eager. Encapsulation is important, but it is as well important for an object to have appropriate API. API which allows for comfortable work.
And what in a situation where a particular operation requires data from a few different objects of different type?
Let’s even simplify the problem! Let’s talk about calculations that need data from different objects of the same class. Simple example can be calculation of average age in group of people, where each person is separate object.
How should we do it?
Should we ask for the age:
1
2
3
4
5
6
7
| Age totalAge = Age.NEWLY_BIRTH; for (Person person : persons) { totalAge = totalAge.add(person.getAge()); } return totalAge.divide(persons.size()); |
Or maybe we should start to think how to solve this by telling objects what we want?
summary
As you can see “Tell, don’t ask” principle cannot be treated like the rule of thumb.We always should keep in mind encapsulation and think at least twice before we would pull out data from the object to the outer world. However, I hope that this article showed you that sometimes it is necessary.
http://martinfowler.com/bliki/TellDontAsk.html
Tell-Don't-Ask is a principle that helps people remember that object-orientation is about bundling data with the functions that operate on that data. It reminds us that rather than asking an object for data and acting on that data, we should instead tell an object what to do. This encourages to move behavior into an object to go with the data.
One of the fundamental principles of object-oriented design is to combine data and behavior, so that the basic elements of our system (objects) combine both together.
This is often a good thing because this data and the behavior that manipulates them are tightly coupled: changes in one cause changes in the other, understanding one helps you understand the other.
This is often a good thing because this data and the behavior that manipulates them are tightly coupled: changes in one cause changes in the other, understanding one helps you understand the other.
https://robots.thoughtbot.com/tell-dont-ask
Good OOP is about telling objects what you want done, not querying an object and acting on its behalf. Data and operations that depend on that data belong in the same object.
<% if current_user.admin? %>
<%= current_user.admin_welcome_message %>
<% else %>
<%= current_user.user_welcome_message %>
<% end %>
+
Better:
+
<%= current_user.welcome_message %>
Not so good:
+
def check_for_overheating(system_monitor)
if system_monitor.temperature > 100
system_monitor.sound_alarms
end
end
+
Better:
+
system_monitor.check_for_overheating
class SystemMonitor
def check_for_overheating
if temperature > 100
sound_alarms
end
end
end
class Post
def send_to_feed
if user.is_a?(TwitterUser)
user.send_to_feed(contents)
end
end
end
+
Better:
+
class Post
def send_to_feed
user.send_to_feed(contents)
end
end
class TwitterUser
def send_to_feed(contents)
twitter_client.post_to_feed(contents)
end
end
class EmailUser
def send_to_feed(contents)
# no-op.
end
end
Not so good:
+
def street_name(user)
if user.address
user.address.street_name
else
'No street name on file'
end
end
+
Better:
1
def street_name(user)
user.address.street_name
end
class User
def address
@address || NullAddress.new
end
end
class NullAddress
def street_name
'No street name on file'
end
end
https://pragprog.com/articles/tell-dont-askProcedural code gets information then makes decisions. Object-oriented code tells objects to do things.
That is, you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do.
The problem is that, as the caller, you should not be making decisions based on the state of the called object that result in you then changing the state of the object. The logic you are implementing is probably the called object’s responsibility, not yours.
For you to make decisions outside the object violates its encapsulation.
http://www.mockobjects.com/2006/10/tell-dont-ask-and-mock-objects.html
objects make decisions using only the information that they hold internally or that they receive as message parameters; they do not make decisions using information that is held by other objects.
That is, objects tell each other what to do by sending commands to one another, they don't ask each other for information and then make decisions upon the results of those queries.
The extreme opposite of the "Tell, Don't Ask" style is "train-wreck" code that contains lots of statements like "object.getPart().getSubpart().getAttribute()" and "object.getPart().getSubpart().setAttribute(x)". In coding style the implementation of one object is coupled to the structure of its neighbours and its neighbours' neighbours, and so it is difficult to replace its neighbour with one that is implemented differently.
This style of code is hard to test with Mock Objects. You find yourself creating lots of mock objects that only exist to let the object under test reach the objects that it actually uses. That's a strong sign that the code needs refactoring: you can simplify the code by introducing new methods in the immediate neighbours of the object under test.
http://blog.iamkoch.com/engineering/development/object-oriented-practises/oo/2014/10/13/oo-principles-tell-dont-ask.html
Other OO Principles:For you to make decisions outside the object violates its encapsulation.
http://www.mockobjects.com/2006/10/tell-dont-ask-and-mock-objects.html
objects make decisions using only the information that they hold internally or that they receive as message parameters; they do not make decisions using information that is held by other objects.
That is, objects tell each other what to do by sending commands to one another, they don't ask each other for information and then make decisions upon the results of those queries.
The extreme opposite of the "Tell, Don't Ask" style is "train-wreck" code that contains lots of statements like "object.getPart().getSubpart().getAttribute()" and "object.getPart().getSubpart().setAttribute(x)". In coding style the implementation of one object is coupled to the structure of its neighbours and its neighbours' neighbours, and so it is difficult to replace its neighbour with one that is implemented differently.
This style of code is hard to test with Mock Objects. You find yourself creating lots of mock objects that only exist to let the object under test reach the objects that it actually uses. That's a strong sign that the code needs refactoring: you can simplify the code by introducing new methods in the immediate neighbours of the object under test.
http://blog.iamkoch.com/engineering/development/object-oriented-practises/oo/2014/10/13/oo-principles-tell-dont-ask.html
public MappedObject Convert(Response response) {
if (ShouldConvertFromBase) // moved from client.
return ConvertFromBase(response);
return CreateFrom(response);
}
Law of Demeter - keep communication to a minimum, don't expose data you don't have to, and keep all logic within the class if possible.
Program to an interface and not an implementation.