I have some questions considering the exercises in "the pragmatic programmer".
It says:
1.
public void showBalance(BankAccount acct) {
Money amt = acct. getBalance() ;
printToScreen(amt .printFormat()) ;
}
The variable acct is passed in as a parameter, so the getBalance call is allowed. Calling amt.printFormat(), however, is not. We don't "own"amt and it wasn't passed to us.
But we do own amt right? It is declared in the method and the LOD states: When your method creates local objects, that method can call methods on the local objects.
Is this example breaking the LOD? The way I see it, it isn't?
2.
public class Colada {
private Blender myBlender;
private Vector myStuff;
public Colada() {
myBlender = new Blender();
myStuff = new Vector() ;
}
private void doSomething() {
myBlender.addlngredients(myStuff.elements());
}
}
Since Colada creates and owns both myBlender and myStuff, the calls to addIngredients and elements are allowed .
Now I don't understand why doSomething is allowed to make calls to myBlender and myStuff since it didn't create it.
3.
void processTransaction(BankAccount acct, int) {
Person *who;
Money amt;
amt.setValue(123.45);
acct.setBalance(amt);
who = acct .getOwner() ;
markWorkflow(who->name(), SET_BALANCE);
}
In this case, processTransaction owns amt, it is created on the stack, acct is passed in, so both setValue and setBalance are allowed. But processTransaction does not own who, so the call who->name() is in violation.
So here it does declare who but it is not allowed to make calls to it. Perhaps I misunderstand the concept of "owns".
Can someone please clarify this?
Thanks
Let's take a look at the supposed contradictions one by one.
1.
public void showBalance(BankAccount acct) {
Money amt = acct. getBalance() ;
printToScreen(amt .printFormat()) ;
}
The variable acct is passed in as a parameter,
so the getBalance call is allowed.
Calling amt.printFormat(), however, is not.
We don't "own" amt and it wasn't passed to us.
This statement is perfectly valid, since LoD states that while acct
can be passed to showBalance()
and showBalance()
can access getBalance()
due to having a direct reference to acct
, it may not call any method on any instance of Money
. This is because no object of type Money
was passed to showBalance()
, and it merely referred to it through a local accessor. This does not mean that the ownership of amt
is now with showBalance()
.
2.
public class Colada {
private Blender myBlender;
private Vector myStuff;
public Colada() {
myBlender = new Blender();
myStuff = new Vector() ;
}
private void doSomething() {
myBlender.addlngredients(myStuff.elements());
}
}
Since Colada creates and owns both myBlender and myStuff,
the calls to addIngredients and elements are allowed .
Now, what is happening in this class constructor is the declaration and instantiation of a Blender
and a Vector
object. Therefore, the owner of myBlender
and myStuff
, is the class Colada
. LoD states that a method m
of object o
can access all direct components of o
, so in this case, method doSomething()
has access to Colada
's components directly, and it may call methods of Blender
and Vector
on myBlender
and myStuff
.
3.
void processTransaction(BankAccount acct, int) {
Person *who;
Money amt;
amt.setValue(123.45);
acct.setBalance(amt);
who = acct .getOwner() ;
markWorkflow(who->name(), SET_BALANCE);
}
In this case, processTransaction owns amt,
it is created on the stack, acct is passed in,
so both setValue and setBalance are allowed.
But processTransaction does not own who,
so the call who->name() is in violation.
The method processTransaction()
receives the the bank account in object acct
. It initializes an object of type Money
, sets the value and then calls the setter method setBalance()
on acct, which is in line with LoD. Since amt
was created and initialized inside processTransaction
, access to setValue
of amt
is also in line with LoD. Now comes the contradiction. *who
is merely a pointer to an object of type Person
, which is only visible through the accessor method getOwner
. But that method is owned by acct
, so calling a method on *who
is invalid, as it breaks LoD.
In short, LoD states that a.getB().getC().doSomething()
is invalid, and only a.getB()
is valid. If I have to write LoD in plain English, it can be specified in 3 words - Chain Of Command
.
Assuming a hierarchy where Object A
contains an instance of Object B
, and Object B
contains an instance of Object C
, the following hold true according to LoD.
I hope that clears your doubts.