You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

学习SOLID原则:依赖倒置原则(DI)为何是开闭原则(OCP)的延伸?

Dependency Inversion Principle (DIP) as an Extension of the Open/Closed Principle (OCP)

Great question! Let’s break this down clearly—since mixing up DIP and DI is such a common pitfall when starting with SOLID, I’m glad you called out that distinction upfront: Dependency Inversion Principle (DIP) is a design principle, while Dependency Injection (DI) is just one implementation technique to follow that principle. They’re related but not interchangeable.

First, let’s recap the core of OCP: it demands that classes/modules should be open for extension, but closed for modification. In plain terms, you should be able to add new features or behavior without hacking into existing, working code. The problem is, how do you structure your code to actually make that possible? That’s where DIP comes in—it’s the principle that enables OCP to work in practice.

DIP’s Core Rules (And How They Enable OCP)

DIP has two non-negotiable tenets:

  • High-level modules (the ones holding your core business logic, like an OrderProcessor) shouldn’t depend on low-level modules (detail-focused code like database handlers, e.g., SqlOrderRepository). Both should depend on abstractions (like an IOrderRepository interface).
  • Abstractions shouldn’t rely on specifics—instead, specifics rely on abstractions. Your interface doesn’t care if you’re using SQL, MongoDB, or a flat file; concrete implementations adapt to the interface, not the other way around.

Example: Violating DIP (And OCP)

Let’s start with a bad example to see why this matters. Suppose you have an order processing system written like this:

// Low-level module (detail-focused)
public class SqlOrderRepository
{
    public void SaveOrder(Order order)
    {
        // SQL-specific save logic here
    }
}

// High-level module (core business logic)
public class OrderProcessor
{
    private readonly SqlOrderRepository _repo;

    public OrderProcessor()
    {
        _repo = new SqlOrderRepository(); // Direct dependency on concrete class
    }

    public void ProcessOrder(Order order)
    {
        // Business logic: validate order, apply discounts, etc.
        _repo.SaveOrder(order);
    }
}

Here, OrderProcessor (high-level) directly depends on SqlOrderRepository (low-level). If you later need to add support for MongoDB, you have to modify OrderProcessor—either add a new constructor, or rewrite the existing one to accept a MongoOrderRepository. That’s a direct violation of OCP: you’re modifying existing code to add new functionality.

Example: Following DIP (And Achieving OCP)

Now let’s refactor this to follow DIP, which automatically makes it OCP-compliant:

// Abstraction (interface)
public interface IOrderRepository
{
    void SaveOrder(Order order);
}

// Low-level module 1: SQL implementation
public class SqlOrderRepository : IOrderRepository
{
    public void SaveOrder(Order order)
    {
        // SQL-specific logic
    }
}

// Low-level module 2: MongoDB implementation (added later, no changes to existing code)
public class MongoOrderRepository : IOrderRepository
{
    public void SaveOrder(Order order)
    {
        // MongoDB-specific logic
    }
}

// High-level module: depends on abstraction, not concrete classes
public class OrderProcessor
{
    private readonly IOrderRepository _repo;

    // Dependency Injection (implementation technique for DIP)
    public OrderProcessor(IOrderRepository repo)
    {
        _repo = repo;
    }

    public void ProcessOrder(Order order)
    {
        // Business logic remains 100% unchanged
        _repo.SaveOrder(order);
    }
}

Now, if you want to add a new storage option (like Redis), you just create a new RedisOrderRepository that implements IOrderRepository—you don’t touch the OrderProcessor at all. That’s OCP in action: extending functionality without modifying existing code.

Why DIP Is an Extension of OCP

OCP sets the goal: extend without modifying. DIP provides the structural blueprint to reach that goal. By decoupling high-level logic from low-level details via abstractions, you create a buffer between the two. Changes to details (like switching databases) don’t require changes to core business logic, because both layers depend on the same abstract contract.

To put it simply: OCP tells you what to aim for, DIP tells you how to structure your code to get there. DI is just one tool to inject those concrete implementations into the high-level modules that depend on the abstractions.

内容的提问来源于stack exchange,提问作者Ezoela Vacca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:17:31