SuperAPI AI Directory

law-of-demeter

Coding & development

View repository

Updated 10-16 06:19

About this skill

Law of Demeter

Talk only to your direct friends. Do not talk to strangers.

Core Principle

A method should call only the methods of its "direct friends" and should not reach for "friends of friends."

Proposed by Karl Liebherr (1987, Northeastern University). The formal name is the "Principle of Least Knowledge."

Approach Characteristic Problem
Chained calls a.getB().getC().doX() Depends on internal structure, fragile to change
Delegation a.doX() Low coupling, resistant to change

Four Rules

Method M may call only the following four kinds of methods:

# Allowed call targets Description
1 Itself (this / self) method Methods defined in its own class
2 M Methods of objects passed as arguments to Direct friends via parameters
3 M Methods of objects created within Objects you created yourself are friends
4 Methods of its own instance variables (fields) Objects you hold are friends

Prohibited: Calling methods on thereturn valueof the above method calls (= friends of friends)

Decision Flow

メソッド内で obj.method() を呼んでいる
    ↓
obj はどこから来たか?
    ├─ this/self のフィールド → ✅ 許可(ルール4)
    ├─ メソッドの引数 → ✅ 許可(ルール2)
    ├─ メソッド内で new/生成した → ✅ 許可(ルール3)
    ├─ this/self 自身 → ✅ 許可(ルール1)
    └─ 別のメソッド呼び出しの戻り値 → ❌ 違反(友人の友人)

Antipattern Detection

Train Wreck

A pattern that follows an object's internal structure through chained dot calls:

❌ order.getCustomer().getAddress().getCity()
❌ user.getProfile().getSettings().getTheme().getName()
❌ app.getConfig().getDatabase().getConnection().execute(query)
❌ invoice.getLineItems().get(0).getProduct().getCategory()

Detection Criteria

Pattern Problem
Chain of two or more dots Structural dependency (though fluent APIs are exceptions)
Getter chain + operation at the end Operating on a retrieved object = friend of a friend
Getter chain + if statement Branching on the state of a distant object

Transformation Patterns

1. Introduce a delegation method

// ❌ 違反: 友人(order)の友人(customer)の友人(address)に話しかけている
City city = order.getCustomer().getAddress().getCity();

// ✅ 修正: 各レベルに委譲メソッドを追加
City city = order.getShippingCity();

// Order
public City getShippingCity() {
    return customer.getShippingCity();
}

// Customer
public City getShippingCity() {
    return address.getCity();
}

2. Method names suited to the purpose

// ❌ 違反: 内部構造を露出した名前
Email email = order.getCustomer().getEmail();

// ✅ 修正: 目的を表すメソッドを提供
Email email = order.getNotificationEmail();

3. Pass as a parameter

// ❌ 違反: 遠いオブジェクトを取得して使用
void processOrder(Order order) {
    PaymentGateway gateway = order.getCustomer().getPaymentGateway();
    gateway.charge(order.getTotal());
}

// ✅ 修正: 必要なオブジェクトを引数で受け取る
void processOrder(Order order, PaymentGateway gateway) {
    gateway.charge(order.getTotal());
}

4. Move behavior to the object

// ❌ 違反: 外部で判定
if (order.getCustomer().getAddress().getCountry().equals("JP")) {
    applyJapaneseTax(order);
}

// ✅ 修正: 判定ロジックをオブジェクトに持たせる
Order orderUpdated = order.applyApplicableTax();

// Order
public Order applyApplicableTax() {
    return customer.applyTaxFor(this);
}

Exceptions: Cases That Are Not Violations

1. Fluent API / Builder pattern

// ✅ 許可: 流暢APIは同一オブジェクトを返す
User user = User.builder()
    .name("Alice")
    .email("alice@example.com")
    .build();

Reason: Because each method returns this , you are not talking to a friend of a friend but continuing to talk to the same friend.

2. Data structures (DTO / Value Object)

// ✅ 許可: DTOは振る舞いを持たない単なるデータ構造
City city = addressDto.getCity();
int zip = addressDto.getZipCode();

Reason: DTOs are not intended to hide internal structure. However, for domain objects it is a violation.

3. Stream / Collection Operations

// ✅ 許可: ストリームAPIの連鎖
List<String> names = users.stream()
    .filter(u -> u.isActive())
    .map(u -> u.getName())
    .collect(Collectors.toList());

Reason: The Stream API is a type of fluent API, not an exploration of internal structure.

4. Standard Library Chaining

# ✅ 許可: 標準ライブラリの連鎖
result = text.strip().lower().replace(" ", "_")

Reason: This is method chaining on the same type (String), not a dependency on internal structure.

Warning on Overapplication

Beware of the "wrapper method explosion"

// 過剰: すべてのフィールドに委譲メソッドを作成
class Order {
    Name getCustomerName() { return customer.getName(); }
    Email getCustomerEmail() { return customer.getEmail(); }
    Phone getCustomerPhone() { return customer.getPhone(); }
    City getCustomerCity() { return customer.getAddress().getCity(); }
    // ... 延々と続く
}

Countermeasure: Delegate only the operations that are truly necessary. Delegating all fields indicates a design problem.

Criteria for Judgment

Situation Response
3 or fewer delegating methods Appropriate
4 or more delegating methods Review the design (consider splitting responsibilities)
A large amount of delegation to the same delegate Consider whether that object should be used directly

Related Principles

Principle Relationship
Tell, Don't Ask Complementary relationship. TDA says "tell", LoD says "only to friends"
Encapsulation LoD is a means of structurally enforcing encapsulation
Loose Coupling Adhering to LoD mechanically reduces coupling
Single Responsibility Principle A wrapper method explosion is a sign of an SRP violation
breach-encapsulation-naming A naming convention that explicitly restricts getters

Review Perspectives

Checkpoints during code review:

  1. Dot chaining: a.b().c() Are there chains of the form with 2 or more levels?
  2. Getter chaining: Is there a pattern of get → get → operate?
  3. Dependency on distant objects: Is the method referencing objects it should not know about?
  4. Checking exceptions: Acceptable for fluent APIs / DTOs / streams

Detailed Guidelines

For language-specific implementation patterns and details of refactoring procedures, see references/patterns.md .

Related Skills (Recommended for Concurrent Reading)

When using this skill, also refer to the following skills:

  • tell-dont-ask: Complementary principle on the behavioral side (tell, don't ask about state)
  • first-class-collection: Pattern for applying the Law of Demeter to collections
  • breach-encapsulation-naming: Naming conventions when chained calls cannot be avoided