Applying the Law of Demeter

Have you ever been told about the Law of Demeter when developing object-oriented systems? This law states the following:

More formally, the Law of Demeter for functions requires that any method M of an object O may only invoke the methods of the following kinds of objects:

  1. itself
  2. its parameters
  3. any objects it creates/instantiates
  4. its direct component objects

In particular, an object should avoid invoking methods of a member object returned by another method.

Browsing the source code of a project, I found this Java code stretch:

   1:public class AccountHelper
   2:{
   3:    public void creditToAccount(Account account, double value)
   4:    {
   5:        double balance = account.balance();
   6:        double newBalance = balance + value;
   7:        account.setBalance(newBalance);
   8:    }
   9:
  10:    public boolean withdrawFromAccount(Account account,
  11:            double value)
  12:    {
  13:        double balance = account.balance();
  14:        double limit = account.limit();
  15:        double newBalance = balance;
  16:        boolean canWithdraw = false;
  17:        if(balance + limit >= value) {
  18:            newBalance = balance - value;
  19:            canWithdraw = true;
  20:        }
  21:        account.setBalance(newBalance);
  22:        return canWithdraw;
  23:    }
  24:}

This code snippet doesn’t follow demeter’s law. And it’s hiding a responsability that would have been better in the Account class. If the Account knows its balance and limit, why putting the credit and withdraw behavior in a helper class? If we follow the Specialist grasp pattern, the responsability has to be at the class with the specific knowledge. So, I’ve improved the design to this new one Java code:

   1:import java.math.BigDecimal;
   2:
   3:public class Account
   4:{
   5:    private BigDecimal balance;
   6:    private BigDecimal limit;
   7:
   8:    public Account(double balance)
   9:    {
  10:        this.balance = new BigDecimal(balance);
  11:    }
  12:
  13:    public Account(double amount,
  14:        double limit)
  15:    {
  16:        this(amount);
  17:        this.limit = new BigDecimal(limit);
  18:    }
  19:
  20:    public void credit(double value)
  21:    {
  22:        balance = balance.add(new BigDecimal(value));
  23:    }
  24:
  25:    public boolean withdraw(double quantity)
  26:    {
  27:        if(canWithdraw(quantity)) {
  28:            balance.subtract(new BigDecimal(quantity));
  29:            return true;
  30:        }
  31:        return false;
  32:    }
  33:
  34:    public double balance()
  35:    {
  36:        return balance.doubleValue();
  37:    }
  38:
  39:    private boolean canWithdraw(double quantity)
  40:    {
  41:        return (balance.doubleValue() + 
  42:                limit.doubleValue() >= quantity)
  43:                ? true
  44:                : false;
  45:    }
  46:
  47:    public void setBalance(double balance)
  48:    {
  49:        this.balance = new BigDecimal(balance);
  50:    }
  51:
  52:    public double limit()
  53:    {
  54:        return limit.doubleValue();
  55:    }
  56:}

So, the initial Java code stretch become this one:

   1:public class AccountHelper
   2:{
   3:    public void credit(Account account, double value)
   4:    {
   5:        assert account != null;
   6:        account.credit(value);
   7:    }
   8:
   9:    public boolean withdraw(Account account, double value)
  10:    {
  11:        assert account != null;
  12:        return account.withdraw(value);
  13:    }
  14:}

This code above is better because we hide from the clients the Account class internal structure (clients don’t need to know the existence of suborders). Moreover, if the internal structure of account is intended to change, less clients would suffer with those changes (actually, if the Account class changes, only it would have to receive the changes and its clients would have to stay far away from its changes. It’s why Object Oriented design is focused in behavior instead of state). This nice phrase resumes demeter’s law: “The resulting software tends to be more maintainable and adaptable. Since objects are less dependent on the internal structure of other objects, object containers can be changed without reworking their callers”.

Leave a Reply

Your email address will not be published. Required fields are marked *