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

Crystal语言中如何实现不依赖框架的Dependency Injection?

Crystal语言无第三方框架依赖的依赖注入实现说明

Crystal标准库目前没有内置的官方依赖注入实现,不过你完全可以手动实现符合需求的DI能力,不需要依赖Athena、Shivneri等第三方框架的相关组件。


常用的零依赖实现方案

1. 构造器注入(最通用的轻量方案)

这是最无需额外代码的DI实现方式,直接通过类构造函数传入依赖即可,示例代码如下:

# 定义依赖的抽象接口
abstract class NotificationService
  abstract def send(message : String) : Nil
end

# 具体实现:邮件通知
class EmailService < NotificationService
  def send(message : String) : Nil
    puts "发送邮件通知: #{message}"
  end
end

# 具体实现:短信通知
class SmsService < NotificationService
  def send(message : String) : Nil
    puts "发送短信通知: #{message}"
  end
end

# 业务类,依赖通过构造器注入,不硬编码具体实现
class OrderService
  def initialize(@notification_service : NotificationService)
  end

  def create_order(order_info : String)
    # 执行订单创建核心逻辑
    @notification_service.send("订单创建成功:#{order_info}")
  end
end

# 调用时按需传入依赖实现
# 注入邮件服务
order_service1 = OrderService.new(EmailService.new)
order_service1.create_order("测试订单001")

# 切换为短信服务仅需修改传入的实例,无需改动OrderService代码
order_service2 = OrderService.new(SmsService.new)
order_service2.create_order("测试订单002")

2. 自定义简易DI容器

如果需要统一管理所有依赖的生命周期、自动组装依赖关系,可以自己实现一个几十行代码的轻量DI容器,完全不需要引入第三方依赖:

class DIContainer
  @[AlwaysInline]
  struct DependencyEntry
    getter impl : Class | Proc, singleton : Bool
    def initialize(@impl, @singleton)
  end

  def initialize
    @dependencies = {} of Symbol => DependencyEntry
    @singleton_instances = {} of Symbol => Any
  end

  # 注册依赖
  def register(key : Symbol, impl : Class | Proc, singleton : Bool = false)
    @dependencies[key] = DependencyEntry.new(impl, singleton)
  end

  # 解析获取依赖实例
  def resolve(key : Symbol)
    entry = @dependencies[key]? || raise "未注册的依赖项:#{key}"
    
    # 单例模式直接返回缓存的实例
    if entry.singleton
      return @singleton_instances[key] if @singleton_instances.has_key?(key)
    end

    # 实例化依赖
    instance = case entry.impl
               when Class then entry.impl.new
               when Proc then entry.impl.call(self)
               end
    
    # 单例实例写入缓存
    if entry.singleton
      @singleton_instances[key] = instance
    end

    instance
  end
end

# 容器使用示例
container = DIContainer.new
# 注册全局单例的通知服务
container.register(:notify_svc, EmailService, singleton: true)
# 注册订单服务,依赖从容器中解析
container.register(:order_svc, ->(c : DIContainer) {
  OrderService.new(c.resolve(:notify_svc))
})

# 直接获取组装完成的订单服务实例
order_service = container.resolve(:order_svc)
order_service.create_order("容器注入测试订单")

3. Setter注入(可选)

如果有运行时动态替换依赖的需求,也可以通过Setter方法实现注入,无需额外框架支持。

上述实现方式都可以覆盖绝大多数中小型项目的DI需求,只有当你需要注解自动注入、依赖自动扫描、复杂生命周期扩展等高级特性时,才需要考虑引入第三方框架的DI组件。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:39:03