Jam*_*ory 6 ruby dependency-injection
Ruby中的依赖注入框架几乎被宣布为不必要的.Jamis Buck去年在他的LEGO,Play-Doh和Programming博客文章中写到了这一点.
普遍接受的替代方案似乎是使用某种程度的构造函数注入,但只是提供默认值.
class A
end
class B
def initialize(options={})
@client_impl = options[:client] || A
end
def new_client
@client_impl.new
end
end
Run Code Online (Sandbox Code Playgroud)
这种方法对我来说很好,但似乎缺少更传统的设置:在运行时基于某些外部开关替换实现的方法.
例如,使用依赖注入框架,我可以做这样的事情(pesudo-C#):
if (IsServerAvailable)
container.Register<IChatServer>(new CenteralizedChatServer());
else
container.Register<IChatServer>(new DistributedChatServer());
Run Code Online (Sandbox Code Playgroud)
此示例仅IChatServer根据我们的中央服务器是否可用来注册不同的实现.
由于我们仍然只是在Ruby中使用构造函数,因此我们没有对所使用的依赖项进行编程控制(除非我们自己指定每个依赖项).Jamis提供的示例似乎非常适合使类更易于测试,但似乎缺少替换设施.
我的问题是,你是如何在Ruby中解决这种情况的?我愿意接受任何答案,包括"你根本不需要这样做".我只是想了解Ruby对这些问题的看法.
除了构造函数替换之外,您还可以将信息存储在实例变量("attribute")中.从你的例子:
class A
end
class B
attr_accessor :client_impl
def connect
@connection = @client_impl.new.connect
end
end
b = B.new
b.client_impl = Twitterbot
b.connect
Run Code Online (Sandbox Code Playgroud)
您还可以允许依赖项作为方法的选项提供:
class A
end
class B
def connect(impl = nil)
impl ||= Twitterbot
@connection = impl.new.connect
end
end
b = B.new
b.connect
b = B.new
b.connect(Facebookbot)
Run Code Online (Sandbox Code Playgroud)
你也可以混合搭配技巧:
class A
end
class B
attr_accessor :impl
def initialize(impl = nil)
@impl = impl || Twitterbot
end
def connect(impl = @impl)
@connection = impl.new.connect
end
end
b = B.new
b.connect # Will use Twitterbot
b = B.new(Facebookbot)
b.connect # Will use Facebookbot
b = B.new
b.impl = Facebookbot
b.connect # Will use Facebookbot
b = B.new
b.connect(Facebookbot) # Will use Facebookbot
Run Code Online (Sandbox Code Playgroud)
基本上,当人们谈论Ruby和DI时,他们的意思是语言本身足够灵活,可以在不需要特殊框架的情况下实现任意数量的DI风格.
| 归档时间: |
|
| 查看次数: |
561 次 |
| 最近记录: |