Token导航 LogoToken导航TokenDH.com
前端设计敏感数据github未标认证来源可访问clear审计通过

dependency-injection依赖注入

Agent Skill

dependency-injection 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

388

周安装

16

GitHub Stars

8

下载量

127
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:dependency-injection(依赖注入)
来源仓库:https://github.com/kaakati/rails-enterprise-dev
仓库路径:skills/dependency-injection
安装命令:
npx skills add https://github.com/kaakati/rails-enterprise-dev --skill dependency-injection
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/kaakati/rails-enterprise-dev --skill dependency-injection

简介

用于 Rails 应用中的依赖注入决策支持。

  • 适用于 Codex、Claude、Cursor、Gemini CLI,支持 GitHub 安装。
  • 提供 DI 模式选择树,判断是否需要注入。
  • 避免在类内部实例化依赖,提升可测性。dependency-injection 属于前端设计类 Skill,可作为该场景下的辅助能力补充。
  • 输出为结构化决策框架,需结合项目实际调整。

SKILL.md

Dependency Injection — Expert Decisions

Expert decision frameworks for dependency injection choices. Claude knows DI basics — this skill provides judgment calls for when and how to apply DI patterns.


Decision Trees

Do You Need DI?

Is the dependency tested independently?
├─ NO → Is it a pure function or value type?
│  ├─ YES → No DI needed (just call it)
│  └─ NO → Consider DI for future testability
│
└─ YES → How many classes use this dependency?
   ├─ 1 class → Simple constructor injection
   ├─ 2-5 classes → Protocol + constructor injection
   └─ Many classes → Consider lightweight container

The trap: DI everything. If a helper function has no side effects and doesn't need mocking, don't wrap it in a protocol.

Which Injection Pattern?

Who creates the object?
├─ Caller provides dependency
│  └─ Constructor Injection (most common)
│     init(service: ServiceProtocol)
│
├─ Object creates dependency but needs flexibility
│  └─ Default Parameter Injection
│     init(service: ServiceProtocol = Service())
│
├─ Dependency changes during lifetime
│  └─ Property Injection (rare, avoid if possible)
│     var service: ServiceProtocol?
│
└─ Factory creates object with dependencies
   └─ Factory Pattern
      container.makeUserViewModel()

Protocol vs Concrete Type

Will this dependency be mocked in tests?
├─ YES → Protocol
│
└─ NO → Is it from external module?
   ├─ YES → Protocol (wrap for decoupling)
   └─ NO → Is interface likely to change?
      ├─ YES → Protocol
      └─ NO → Concrete type is fine

Rule of thumb: Network, database, analytics, external APIs → Protocol. Date formatters, math utilities → Concrete.

DI Container Complexity

Team size?
├─ Solo/Small (1-3)
│  └─ Default parameters + simple factory
│
├─ Medium (4-10)
│  └─ Simple manual container
│     final class Container {
│         lazy var userService = UserService()
│     }
│
└─ Large (10+)
   └─ Consider Swinject or similar
      (only if manual wiring becomes painful)

NEVER Do

Protocol Design

NEVER create protocols with only one implementation:

// ❌ Protocol just for the sake of it
protocol DateFormatterProtocol {
    func format(_ date: Date) -> String
}

class DateFormatterImpl: DateFormatterProtocol {
    func format(_ date: Date) -> String { ... }
}

// ✅ Just use the type directly
let formatter = DateFormatter()
formatter.dateStyle = .medium

Exception: When wrapping external dependencies for decoupling or testing.

NEVER mirror the entire class interface in a protocol:

// ❌ 1:1 mapping is a code smell
protocol UserServiceProtocol {
    var users: [User] { get }
    var isLoading: Bool { get }
    func fetchUser(id: String) async throws -> User
    func updateUser(_ user: User) async throws
    func deleteUser(id: String) async throws
    // ...20 more methods
}

// ✅ Minimal interface for what's actually needed
protocol UserFetching {
    func fetchUser(id: String) async throws -> User
}

NEVER put mutable state requirements in protocols:

// ❌ Forces implementation details
protocol CacheProtocol {
    var storage: [String: Any] { get set }  // Leaks implementation
}

// ✅ Behavior-focused
protocol CacheProtocol {
    func get(key: String) -> Any?
    func set(key: String, value: Any)
}

Constructor Injection

NEVER use property injection when constructor injection works:

// ❌ Object can be in invalid state
class UserViewModel {
    var userService: UserServiceProtocol!  // Can be nil!

    func loadUser() async {
        let user = try? await userService.fetchUser(id: "1")  // Crash if not set!
    }
}

// ✅ Guaranteed valid state
class UserViewModel {
    private let userService: UserServiceProtocol

    init(userService: UserServiceProtocol) {
        self.userService = userService  // Never nil
    }
}

NEVER create objects with many dependencies (> 5):

// ❌ Too many dependencies — class does too much
init(
    userService: UserServiceProtocol,
    authService: AuthServiceProtocol,
    analyticsService: AnalyticsProtocol,
    networkManager: NetworkManagerProtocol,
    cacheManager: CacheProtocol,
    configService: ConfigServiceProtocol,
    featureFlagService: FeatureFlagProtocol
) { ... }

// ✅ Split into smaller, focused classes
// Or create a composite service

Service Locator (Anti-Pattern)

NEVER use Service Locator pattern:

// ❌ Hidden dependencies, runtime errors, untestable
class UserViewModel {
    func loadUser() async {
        let service = ServiceLocator.shared.resolve(UserServiceProtocol.self)!
        // Crashes if not registered
        // Dependency is hidden
        // Can't see what this class needs
    }
}

// ✅ Explicit constructor injection
class UserViewModel {
    private let userService: UserServiceProtocol  // Visible dependency

    init(userService: UserServiceProtocol) {
        self.userService = userService
    }
}

Testing

NEVER create mocks with real side effects:

// ❌ Mock does real work
class MockNetworkManager: NetworkManagerProtocol {
    func request<T>(_ endpoint: Endpoint) async throws -> T {
        // Actually makes network call!
        return try await URLSession.shared.data(from: endpoint.url)
    }
}

// ✅ Mocks return stubbed data
class MockNetworkManager: NetworkManagerProtocol {
    var stubbedResult: Any?
    var stubbedError: Error?

    func request<T>(_ endpoint: Endpoint) async throws -> T {
        if let error = stubbedError { throw error }
        return stubbedResult as! T
    }
}

NEVER test mocks instead of real code:

// ❌ Testing the mock, not the system
func testMockReturnsUser() {
    let mock = MockUserService()
    mock.stubbedUser = User(name: "John")
    XCTAssertEqual(mock.fetchUser().name, "John")  // Tests mock, not app
}

// ✅ Test the system under test
func testViewModelLoadsUser() async {
    let mock = MockUserService()
    mock.stubbedUser = User(name: "John")

    let viewModel = UserViewModel(userService: mock)  // SUT
    await viewModel.loadUser(id: "1")

    XCTAssertEqual(viewModel.user?.name, "John")  // Tests ViewModel
}

Essential Patterns

Default Parameter Injection

// Production uses real, tests inject mock
@MainActor
final class UserViewModel: ObservableObject {
    private let userService: UserServiceProtocol

    init(userService: UserServiceProtocol = UserService()) {
        self.userService = userService
    }
}

// Production
let viewModel = UserViewModel()

// Test
let viewModel = UserViewModel(userService: MockUserService())

Simple Manual Container

@MainActor
final class Container {
    static let shared = Container()

    // Singletons (lazy initialized)
    lazy var networkManager: NetworkManagerProtocol = NetworkManager()
    lazy var authService: AuthServiceProtocol = AuthService(network: networkManager)
    lazy var userService: UserServiceProtocol = UserService(network: networkManager)

    // Factory methods (new instance each time)
    func makeUserViewModel() -> UserViewModel {
        UserViewModel(userService: userService)
    }

    func makeLoginViewModel() -> LoginViewModel {
        LoginViewModel(authService: authService)
    }
}

SwiftUI Environment Injection

// Custom environment key
private struct UserServiceKey: EnvironmentKey {
    static let defaultValue: UserServiceProtocol = UserService()
}

extension EnvironmentValues {
    var userService: UserServiceProtocol {
        get { self[UserServiceKey.self] }
        set { self[UserServiceKey.self] = newValue }
    }
}

// Inject at app level
@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.userService, Container.shared.userService)
        }
    }
}

// Consume in any view
struct UserView: View {
    @Environment(\.userService) var userService

    var body: some View {
        // Use userService
    }
}

Mock with Verification

final class MockUserService: UserServiceProtocol {
    // Stubbed returns
    var stubbedUser: User?
    var stubbedError: Error?

    // Call tracking
    private(set) var fetchUserCallCount = 0
    private(set) var fetchUserLastId: String?

    func fetchUser(id: String) async throws -> User {
        fetchUserCallCount += 1
        fetchUserLastId = id

        if let error = stubbedError { throw error }
        guard let user = stubbedUser else {
            throw MockError.notStubbed
        }
        return user
    }
}

// Test with verification
func testFetchesCorrectUser() async {
    let mock = MockUserService()
    mock.stubbedUser = User(id: "123", name: "John")

    let viewModel = UserViewModel(userService: mock)
    await viewModel.loadUser(id: "123")

    XCTAssertEqual(mock.fetchUserCallCount, 1)
    XCTAssertEqual(mock.fetchUserLastId, "123")
}

Quick Reference

When to Use Each Pattern

PatternUse WhenAvoid When
Constructor injectionDefault choiceNever avoid
Default parametersConvenience with testabilityDependency changes at runtime
Property injectionFramework requires it (rare)You have control over init
FactoryObject needs runtime parametersSimple object creation
ContainerMany cross-cutting dependenciesSmall app, few dependencies

Protocol Checklist

  • Will it be mocked? If no, skip protocol
  • Interface is minimal (only needed methods)
  • No mutable state requirements
  • No implementation details leaked
  • Single responsibility

DI Red Flags

SmellProblemFix
Protocol for every classOver-engineeringOnly where needed
Service LocatorHidden dependenciesConstructor injection
> 5 constructor paramsClass does too muchSplit responsibilities
Property injectionObject can be invalidConstructor injection
Mock does real workTests are slow/flakyReturn stubbed data
1:1 protocol:class ratioUnnecessary abstractionRemove unused protocols

SwiftUI DI Comparison

PatternScopeUse For
@EnvironmentView hierarchySystem/app services
@EnvironmentObjectView hierarchyObservable shared state
@StateObject init injectionSingle viewView-specific ViewModel
Container factoryApp-wideComplex dependency graphs

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Antigravity

26.3%
按下载量换算33

windsurf

24.24%
按下载量换算31

Claude Code

18.78%
按下载量换算24

OpenCode

11.3%
按下载量换算14

Gemini CLI

7.92%
按下载量换算10

Codex

3.22%
按下载量换算4

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills