Law of Demeter (also known as the Principle of Least Knowledge) states that an object should only talk to its immediate neighbors, not to strangers.

Core Concept

A method of an object should only call methods on:

  1. The object itself
  2. Objects passed as parameters
  3. Objects it creates
  4. Its direct component objects

The Problem: Train Wrecks

Bad Example (Violates Law of Demeter)

// BAD: Chaining through multiple objects
public class OrderProcessor
{
    public void ProcessOrder(Order order)
    {
        string zipCode = order.GetCustomer().GetAddress().GetZipCode();
        // This knows too much about Order's internal structure
    }
}

This is called a “train wreck” - each method call is a car in the train. This code:

  • Creates tight coupling across multiple classes
  • Breaks encapsulation
  • Makes refactoring difficult
  • Violates the single responsibility principle

Good Example (Follows Law of Demeter)

// GOOD: Ask the object directly for what you need
public class Order
{
    private Customer _customer;
 
    public string GetShippingZipCode()
    {
        return _customer.GetZipCode(); // Order handles its own navigation
    }
}
 
public class Customer
{
    private Address _address;
 
    public string GetZipCode()
    {
        return _address.ZipCode; // Customer handles its own navigation
    }
}
 
public class OrderProcessor
{
    public void ProcessOrder(Order order)
    {
        string zipCode = order.GetShippingZipCode(); // Clean, focused call
    }
}

Why It Matters

  • Loose Coupling: Changes to intermediate objects don’t cascade
  • Encapsulation: Internal structure remains hidden
  • Maintainability: Easier to understand and modify
  • Testability: Fewer dependencies to mock

When to Relax This Rule

The Law of Demeter can be relaxed for:

  • Fluent APIs: Intentionally designed for chaining
  • Data Structures: DTOs and simple data containers
  • Query Objects: Read models designed for traversal
// OK: Fluent API intentionally designed for chaining
var query = dbContext.Users
    .Where(u => u.IsActive)
    .OrderBy(u => u.Name)
    .Select(u => u.Email);