依存関係

1 件の記事

Contents

A class must: 1. Explicitly receive all dependencies (via DI) — it should not secretly rely on any helper. 2. Maintain a consistent responsibility. (クラスは次を満たす必要がある:1. すべての依存関係を明示的に受け取る(DI経由)— ヘルパーに密かに依存してはいけない。2. 一貫した責任を維持する)

解説

依存関係が暗黙的だと、テストやデバッグが困難になり、コードの理解に時間がかかります。すべての依存関係をコンストラクタで明示的に注入することで、クラスが必要とするものが一目でわかり、モックやスタブを使ったテストが容易になります。また、一貫した責任を維持することで、クラスの目的が明確になり、変更の影響範囲が限定されます。これは保守性の高いコード設計の基本原則です。

具体例

// 悪い例(暗黙的な依存)
type OrderService struct {
    // 依存関係が明示されていない
}

func (s *OrderService) CreateOrder(items []Item) error {
    // 内部でグローバルなhelperを使用
    db := GetGlobalDB()  // 暗黙的な依存
    logger := GetGlobalLogger()  // 暗黙的な依存

    total := calculateTotal(items)
    if err := db.Insert(total); err != nil {
        logger.Error(err)
        return err
    }
    return nil
}

// 良い例(明示的な依存注入)
type OrderService struct {
    db     Database
    logger Logger
    pricer PriceCalculator
}

func NewOrderService(db Database, logger Logger, pricer PriceCalculator) *OrderService {
    return &OrderService{
        db:     db,
        logger: logger,
        pricer: pricer,
    }
}

func (s *OrderService) CreateOrder(items []Item) error {
    total := s.pricer.CalculateTotal(items)

    if err := s.db.Insert(total); err != nil {
        s.logger.Error(err)
        return err
    }

    return nil
}

参考リンク