c# – 用于静态类型语言的标准DI模式的JavaScript DI / IoC等效
.NET和
Java都有一大堆DI / IoC容器可供它们使用
我发现有很多模式在不同的点上非常有用 与他们合作.我现在正处于我想做同等事情的地步 JavaScript中的东西.由于JavaScript是一种动态语言,我没想到 DI / IoC容器与所提供的所有功能直接等效 通过静态类型语言中找到的容器可以替代这些容器 模式是受欢迎的.我还期望可以使用DI / IoC容器 JavaScript的功能会有所不同,所以引用会有所不同 容器非常受欢迎. 以下模式是我认为的Autofac 3支持的模式 与JavaScript中下面描述的概念和模式最接近的等价物是什么? 一般概念 概念1:向IoC容器注册 在IoC容器可以创建类型的实例之前,需要注意 class A {} var builder = new ContainerBuilder(); builder.RegisterType<A>(); 以上使IoC容器知道类型A.它发现A的 class B {} class A { A(string name,B b) { } } builder.RegisterType<B>(); builder.Register(c => // c is a reference to the created container new A("-name-",c.Resolve<B>())); 能够提供工厂功能在您拥有时非常有用 由于C#支持接口和抽象类,因此通常不支持 interface IPlugin {} class P : IPlugin builder.RegisterType<P>().As<IPlugin>(); 通过上述注册,任何请求P的尝试都会失败,但是a 概念2:容器创造&组成根 一旦完成所有注册,容器就需要 public class Program { public static void Main(string[] args) { var builder = new ContainerBuilder(); /* perform registrations on builder */ var container = builder.Build(); /* do something useful with container */ } } 容器是在程序生命周期的早期创建的,并且成为了 public static void Main(string[] args) { var builder = new ContainerBuilder(); /* perform registrations on builder */ var container = builder.Build(); var application = container.Resolve<Application>(); application.Launch(); } 概念3:终身&实例管理 鉴于: class A {} 如果我们想要为每个依赖项创建一个新的A实例,它可以是 如果我们希望每次需要返回相同的A实例 builder.RegisterType<A>().SingleInstance(); 有时我们想在一定范围内共享一个实例但是 builder.RegisterType<A>().InstancePerLifetimeScope(); var scope = container.BeginLifetimeScope(); // within the request's scope var root = scope.Resolve<RequestProcessor>(); root.Process(); 一般模式 模式1:A需要B的实例 class B {} // registered as: builder.RegisterType<B>() class A { // registered as: builder.RegisterType<A>() A(B b) {} } var a = container.Resolve<A>(); IoC容器使用反射来发现对B和注入的依赖 模式2:A在将来的某个时刻需要B class B {} class A { A(Lazy<B> lazyB) { // when ready for an instance of B: try { var b = lazyB.Value; } catch (DependencyResolutionException) { // log: unable to create an instance of B } } } 在这种模式中,依赖关系的实例化需要延迟 模式3:需要创建B的实例 class B {} class A { A(Func<B> factory) { try { // frequently called multiple times var b = factory.Invoke(); } catch (DependencyResolutionException) { // log: Unable to create } } } 当需要创建多个时,通常使用此模式 模式4:A将类型X和Y的参数提供给B. class X {} class Y {} class B { B(X x,Y y) { } } 通常在需要注入依赖项时使用此模式 class DAO { DAO(string connectionString) {} } class A { A(Func<DAO> daoFactory) { var dao = daoFactory.Invoke("DATA SOURCE=..."); var datum = dao.Get<Data>(); } } 模式5:A需要各种B interface IPlugin {} class X: IPlugin {} // builder.RegisterType<X>().As<IPlugin>() class Y: IPlugin {} // builder.RegisterType<Y>().As<IPlugin>() class Z: IPlugin {} // builder.RegisterType<Z>().As<IPlugin>() class A { A(IEnumerable<IPlugin> plugins) { foreach (var plugin in plugins) { // Add all plugins to menu } } } 在该模式中,对给定类型进行多次注册.消费者 模式6:A需要知道B,或者A需要知道关于B的X. class B {} // builder.RegisterType<B>().WithMetadata("IsActive",true); // A needs to know about B class A { A(Meta<B> metaB) { if ((bool)metaB.Metadata["IsActive"]) { // do something intelligent... } } } // OR... class B {} // builder.RegisterType<C>().WithMetadata<X>(...); class X { bool IsActive { get; } } // A needs to know X about B class A { A(Meta<B,X> metaB) { if (metaB.IsActive) { // do something intelligent... } } } 让我们再次说我们有一个使用插件的系统.插件可能是 模式7:上述模式的组成 interface IPlugin: class Plugin1 : IPlugin {} class Plugin2 : IPlugin {} class Plugin3 : IPlugin {} class PluginUser { PluginUser(IEnumerable<Lazy<IPlugin>> lazyPlugins) { var plugins = lazyPlugins .Where(CreatePlugin) .Where(x => x != null); // do something with the plugins } IPlugin CreatePlugin(Lazy<IPlugin> lazyPlugin) { try { return lazyPlugin.Value; } catch (Exception ex) { // log: failed to create plugin return null; } } } 在此代码示例中,我们请求包含在Lazy对象中的所有插件的列表 模式8:适配器 这个例子取自: interface ICommand {} class SaveCommand: ICommand {} class OpenCommand: ICommand {} var builder = new ContainerBuilder(); // Register the services to be adapted builder.RegisterType<SaveCommand>() .As<ICommand>() .WithMetadata("Name","Save File"); builder.RegisterType<OpenCommand>() .As<ICommand>() .WithMetadata("Name","Open File"); // Then register the adapter. In this case,the ICommand // registrations are using some metadata,so we're // adapting Meta<ICommand> instead of plain ICommand. builder.RegisterAdapter<Meta<ICommand>,ToolbarButton>( cmd => new ToolbarButton(cmd.Value,(string)cmd.Metadata["Name"])); var container = builder.Build(); // The resolved set of buttons will have two buttons // in it - one button adapted for each of the registered // ICommand instances. var buttons = container.Resolve<IEnumerable<ToolbarButton>>(); 以上允许注册的所有命令自动适应 模式9:装饰者 interface ICommand { string Name { get; } bool Execute(); } class SaveCommand : ICommand {} class OpenCommand : ICommand {} class LoggingCommandDecorator: ICommand { private readonly ICommand _cmd; LoggingCommandDecorator(ICommand cmd) { _cmd = cmd; } bool Execute() { System.Console.WriteLine("Executing {0}",_cmd.Name); var result = _cmd.Execute(); System.Console.WriteLine( "Cmd {0} returned with {1}",_cmd.Name,result); return result; } } // and the corresponding registrations builder.RegisterType<SaveCommand>().Named<ICommand>("command"); builder.RegisterType<OpenCommand>().Named<ICommand>("command"); builder.RegisterDecorator<ICommand>((c,inner) => new LoggingCommandDecorator(inner),fromKey: "command"); // all ICommand's returned will now be decorated with the // LoggingCommandDecorator. We could,almost equivalently,use // AOP to accomplish the same thing. 摘要 首先,尽管我试图使这些示例合理地代表所描述的模式,但这些是说明性的玩具示例,由于空间限制可能不是理想的.对我来说更重要的是 与JavaScript中下面描述的概念和模式最接近的等价物是什么? 解决方法
您提到的一些功能是通过使用AMD实现的.
例如,请看RequireJS: http://requirejs.org/docs/whyamd.html 另一个值得关注的实现是Angular JS DI: 您可以轻松注入模块(封装和元数据中包含的功能单元) 希望能帮助到你 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |