面试题答案
一键面试Dry::Container工作原理分析
- 对象生命周期管理:
- Dry::Container使用惰性加载机制。当对象被注册后,只有在实际需要解析(获取)该对象时才会创建它。例如,假设注册了一个数据库连接对象:
这里require 'dry/container' container = Dry::Container.new container.register(:db_connection) do require 'pg' PG.connect(dbname: 'test') end
db_connection
对象只有在调用container[:db_connection]
时才会真正创建,这样可以避免在应用启动时就创建大量可能不需要的对象,提高启动性能。- 对于单例对象,Dry::Container提供了专门的方法进行管理。比如:
这样无论多少次调用container.register(:config, singleton: true) do require 'yaml' YAML.load_file('config.yml') end
container[:config]
,返回的都是同一个实例,保证了配置对象在整个应用中的一致性。 - 处理依赖关系:
- Dry::Container支持依赖的自动解析。当一个对象的创建依赖于其他对象时,容器可以自动处理这些依赖。例如:
这里container.register(:user_repository) do require_relative 'user_repository' UserRepository.new(container[:db_connection]) end
user_repository
的创建依赖于db_connection
,容器在解析user_repository
时,会先确保db_connection
被创建并注入到UserRepository
的构造函数中。
自定义简单依赖注入框架
- 设计思路:
- 首先,我们需要一个容器类来管理所有注册的对象。这个容器类应该有方法来注册对象和解析对象。
- 对于对象注册,我们可以使用一个哈希表来存储注册的对象及其创建逻辑。
- 在解析对象时,如果对象的创建依赖其他对象,我们递归地解析这些依赖,确保所有依赖对象都被正确创建并注入。
- 代码实现:
class MyDependencyInjector
def initialize
@registry = {}
end
def register(key, &block)
@registry[key] = block
end
def resolve(key)
raise "Object not registered: #{key}" unless @registry.key?(key)
block = @registry[key]
dependencies = block.parameters.map { |_, name| resolve(name) }
block.call(*dependencies)
end
end
可以这样使用:
injector = MyDependencyInjector.new
injector.register(:db_connection) do
require 'pg'
PG.connect(dbname: 'test')
end
injector.register(:user_repository) do |db_connection|
require_relative 'user_repository'
UserRepository.new(db_connection)
end
user_repo = injector.resolve(:user_repository)
在这个实现中,register
方法用于注册对象及其创建逻辑。resolve
方法负责解析对象,如果对象依赖其他对象,会先递归解析依赖对象并注入到创建逻辑中。