Friday, May 20, 2011

Principle of least knowledge or Law of Demeter (LOD)

The principle states: Each unit should only talk to its friends; Don’t talk to strangers. A method of an object should invoke only the methods of the following kinds of objects:
    1. itself 2. its parameters 3. any objects it creates/instantiates 4. its direct component objects

Violation of above principle

Below is an example of some code breaking this principle:
Interface : IOrderManager

public interface IOrderManager
{
void AddItemToOrder(IItem item);
void RemoveItemFromOrder(IItem item);
void ChangeItemName(IItem item, string name);
}


Interface: IItem


public interface IItem
{
int Id { get; set; }
string Name { get; set; }
}

Class: Item : IItem

public class Item : IItem
{
private int _Id;
private string _Name;

public int Id
{
get { return _Id; }
set { _Id = value; }
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
}
Class :OrderManager : IOrderManager

public class OrderManager implements IOrderManager
{
private IOrder _Order;

public OrderManager()
{
_Order = new Order();
_Order.Items = new List<IItem>();
}

public void AddItemToOrder(IItem item)
{
if (_Order.Items != null)
{
if ( ! _Order.Items.Contains(item))
{
_Order.Items.Add(item);
}
}
}
public void RemoveItemFromOrder(IItem item)
{
if (_Order.Items != null)
{
if (_Order.Items.Contains(item))
{
_Order.Items.Remove(item);
}
}
}
public void ChangeItemName(IItem item, string name)
{
if (_Order.Items != null)
{
if (_Order.Items.Contains(item))
{
_Order.Items[_Order.Items.IndexOf(item)].Name = name;
}
}
}

In the above example the OrderManager has the responsibility of adding and removing Items to and from the List collection in the Order class, and even worse it has the responsibility of changing the name of a particular Item inside that collection. This tightly couples the OrderManager to the Order and Item class, if we would change how the Order class is maintaining her Items than we automatically have to change the OrderManager class. The Order should be responsible for its Items, not the OrderManager. Below is the Law Of Demeter implementation of this example:
Interface: IOrder



public interface IOrder
{
void AddItem(IItem item);
void RemoveItem(IItem item);
void ChangeItemName(IItem item, string name);
}


Class: Order : IOrder


public class Order implements IOrder
{
private List<IItem> _Items;

public Order()
{
_Items = new List<IItem>();
}

public void AddItem(IItem item)
{
if (_Items != null)
{
if (!_Items.Contains(item))
{
_Items.Add(item);
}
}
}
public void RemoveItem(IItem item)
{
if (_Items != null)
{
if (_Items.Contains(item))
{
_Items.Remove(item);
}
}
}
public void ChangeItemName(IItem item, string name)
{
if (_Items != null)
{
if (_Items.Contains(item))
{
_Items[_Items.IndexOf(item)].Name = name;
}
}
}
}

Class: OrderManager : IOrderManager


public class OrderManager implements IOrderManager
{
private IOrder _Order;

public OrderManager()
{
_Order = new Order();
}

public void AddItemToOrder(IItem item)
{
_Order.AddItem(item);
}
public void RemoveItemFromOrder(IItem item)
{
_Order.RemoveItem(item);
}
public void ChangeItemName(IItem item, string name)
{
_Order.ChangeItemName(item, name);
}
}

Now we can change how the Order class is keeping its Items without having to change the OrderManager. One nice rule of thumb is: One dot should be enough.

No comments:

Post a Comment

Chitika