FactoryMethodsUsingDIandIoCFactoryMethodsUsingDIandIoC我很熟悉这些模式,但仍然不知道如何处理以下情况:publicclassCarFactory{publicCarFactory(Dep1,Dep2,Dep3,Dep4,Dep5,Dep6){}publicICarCreateCar(type){switch(type){caseA:returnnewCar1(Dep1,Dep2,Dep3);休息;情况B:返回新的Car2(Dep4,Dep5,Dep6);休息;通常,问题在于需要注入的引用数量。当有更多的汽车时更糟。我想到的第一个方法是在工厂构造函数中注入Car1和Car2,但它违反了工厂方法,因为工厂将始终返回相同的对象。第二种方法是注入servicelocator但它的反模式无处不在。如何处理?编辑:备选方案1:publicclassCarFactory{publicCarFactory(IContainercontainer){_container=container;}publicICarCreateCar(type){switch(type){caseA:return_container.Resolve();休息;情况B:返回_container.Resolve();休息;}}}备选方案2(由于树中的依赖项太多而难以使用):publicclassCarFactory{publicCarFactory(){}publicICarCreateCar(type){switch(type){(),newDep2(newDep683(),newDep684()),....)中断;情况B:返回newCar2(newDep4(),newDep5(newDep777(),newDep684()),....)中断;}}}在工厂里有一个switchcase语句是一种代码味道。有趣的是你似乎根本没有专注于解决这个问题。对于这种情况,最好和最友好的DI解决方案是Strategy模式。它允许您的DI容器将依赖项注入到它们所属的工厂实例中,而不会使其他类与这些依赖项混淆或求助于服务定位器。接口publicinterfaceICarFactory{ICarCreateCar();布尔适用于(类型类型);}publicinterfaceICarStrategy{ICarCreateCar(类型类型);}工厂publicclassCar1Factory:ICarFactory{privatereadonlyIDep1dep1;私有只读IDep2dep2;私人只读IDep3dep3;publicCar1Factory(IDep1dep1,IDep2dep2,IDep3dep3){if(dep1==null)thrownewArgumentNullException("dep1");如果(dep2==null)抛出新的ArgumentNullException("dep2");如果(dep3==null)抛出新的ArgumentNullException("dep3");这个.dep1=dep1;这个.dep2=dep2;这个.dep3=dep3;}publicICarCreateCar(){returnnewCar1(this.dep1,this.dep2,this.dep3);}publicboolAppliesTo(Typetype){returntypeof(Car1).Equals(type);}}publicclassCar2Factory:ICarFactory{privatereadonlyIDep4dep4;私有只读IDep5dep5;私有只读IDep6dep6;publicCar1Factory(IDep4dep4,IDep5dep5,IDep6dep6){if(dep4==null)thrownewArgumentNullException("dep4");如果(dep5==null)抛出新的ArgumentNullException("dep5");如果(dep6==null)抛出新的ArgumentNullException("dep6");这个.dep4=dep4;这个.dep5=dep5;这个.dep6=dep6;}publicICarCreateCar(){returnnewCar2(this.dep4,this.dep5,this.dep6);}publicboolAppliesTo(Typetype){returntypeof(Car2).Equals(type);}}战略publicclassCarStrategy:ICarStrategy{privatereadonlyICarFactory[]carFactories;publicCarStrategy(ICarFactory[]carFactories){如果(carFactories==null)thrownewArgumentNullException("carFactories");this.carFactories=carFactories;}publicICarCreateCar(Typetype){varcarFactory=this.carFactories.FirstOrDefault(factory=>factory.AppliesTo(type));if(carFactory==null){thrownewException("typenotregistered");}返回carFactory.CreateCar();}}用法//我在代码中展示了这个,但是你通常会//??在你的合成根目录中使用你的DI容器来做这个//实例将是cre//通过在某处注入它来进行。varstrategy=newCarStrategy(newICarFactory[]{newCar1Factory(dep1,dep2,dep3),newCar2Factory(dep4,dep5,dep6)});//然后一旦它被注入,你就可以简单地这样做。//请注意,如果您愿意,可以使用魔术字符串或其他//数据类型作为参数。varcar1=strategy.CreateCar(typeof(Car1));varcar2=strategy.CreateCar(typeof(Car2));请注意,由于没有switchcase语句,您可以在不更改设计的情况下向策略添加额外的工厂,并且每个工厂都可以通过DI容器varstrategy=newCarStrategy(newICarFactory[]{newCar1Factory(dep1,dep2,dep3),newCar2Factory(dep4,dep5,dep6),newCar3Factory(dep7,dep8,dep9)});varcar1=策略。CreateCar(typeof(Car1));varcar2=strategy.CreateCar(typeof(Car2));varcar3=strategy.CreateCar(typeof(Car3));使用CompositionRoot聚合您对代码示例的评论。您可以创建以下内容,但这不是服务定位器。publicclassCarFactory{privatereadonlyFunccarFactory;publicCarFactory(FunccarFactory){this.carFactory=carFactory;}publicICarCreateCar(TypecarType){returncarFactory(carType);carFactoryFunc=type=>(ICar)container.Resolve(type);container.RegisterInstance(新CarFactory(carFactoryFunc));我刚才回答过类似的问题。基本上是你的选择。您必须在冗长(这对编译器有更多帮助)和自动化之间做出选择,后者允许您编写更少的代码,但更容易出错。这是我冗长的回答。这也是支持自动化的一个很好的答案。编辑我相信你认为错误的方法实际上是最好的。老实说,通常没有那么多依赖关系。我喜欢这种方法,因为它非常明确并且很少导致运行时错误。备选方案1:这个很烂。它实际上是一个服务定位器,被认为是一种反模式。备选方案2就像你写的那样,如果与IOCincludes混合使用并不容易。然而,在某些情况下,类似的方法(穷人的DI)可能会有用。总而言之,我不打算在您的工厂中有“很多”依赖项。这是简单的声明性代码。写入只需几秒钟,为您节省数小时与运行时错误作斗争的时间。我会考虑给依赖关系一个很好的结构,这样你就可以使用类似于Wiktor的答案的东西,但我会抽象出汽车工厂本身。然后你不使用if..then构造。公共接口ICar{字符串Make{get;放;}stringModelNumber{得到;放;}IBody身体{得到;放;}//IEngine引擎{get;放;}//更多方面...等。}publicinterfaceIBody{//IDoorDoorA{get;放;}//IDoorDoorB{get;放;}//etc}//对各种规格进行分组publicinterfaceIBodySpecs{//intNumberOfDoors{get;放;}//intNumberOfWindows{得到;放;}//字符串颜色{get;放;}}publicinterfaceICarSpecs{IBodySpecsBodySpecs{get;放;}//IEngineSpecsEngineSpecs{get;放;}//ETC。}publicinterfaceICarFactorywhereTCar:ICarwhereTCarSpecs:ICarSpecs{//Asynccauseeverythingnon-trivialshouldbeIMHO!任务CreateCar(TCarSpecscarSpecs);//而不是依赖构造函数注入或方法注入//现在,你不用处理复杂的重载IService1Service1{get;放;}IBuilder1Builder1{得到;放;}}publicclassBaseCar:ICar{publicstringMake{get;放;}公共字符串ModelNumb呃{得到;放;}公共IBody身体{得到;放;}//publicIEngine引擎{get;放;}}publicclassVan:BaseCar{publicstringVanStyle{get;放;}//ETC。}publicinterfaceIVanSpecs:ICarSpecs{stringVanStyle{get;放;}}publicclassVanFactory:ICarFactory{//既然你在谈论如此大量的依赖项,//如果它们是汽车或//汽车工厂依赖项,你可能需要正确分类//这些是在工厂本身中注入的公共IBuilder1Builder1{得到;放;}publicIService1Service1{get;放;}publicasyncTaskCreateCar(IVanSpecscarSpecs){varvan=newVan(){//在这里创建实际的实现。};//等待某物或其他返回货车;我没有列出它,但你现在可以实现多种类型的汽车及其相应的工厂,并使用DI注入你首先需要的任何东西,你有一个具体的工厂,一个IoC容器可能是一个替代品,而不是帮你。然后,只需重构工厂,不要指望工厂构造函数中可能参数的完整列表。这是主要问题-如果工厂方法不需要它们,为什么要传递这么多参数?我宁愿将特定参数传递给工厂方法publicabstractclassCarFactoryParams{}publicclassCar1FactoryParams:CarFactoryParams{publicCar1FactoryParams(Dep1,Dep2,Dep3){this.Dep1=Dep1;...}publicclassCar2FactoryParams...publicclassCarFactory{publicICarCreateCar(CarFactoryParamsparams){if(paramsisCar1FactoryParams){varcp=(Car1FactoryParams)params;返回新Car1(cp.Dep1,cp.Dep2,...);}...if(paramsis...通过将参数列表封装在特定类中,您只需让客户端提供特定工厂方法调用所需的参数。编辑:不幸的是,从您的帖子中不清楚这些Dep1是...以及如何使用它们。我推荐以下方法将工厂提供者与实际工厂实现分开。这种方法称为本地工厂模式:publicclassCarFactory{privatestaticFunc_provider;publicstaticvoidSetProvider(Funcprovider){_provider=provider;}publicICarCreateCar(type){return_provider(type);}}工厂本身没有任何实现,它是为你的域API设置基础,你只想使用它创建汽车实例。然后,在CompositionRoot(靠近您配置实际容器的应用程序的开头)配置提供者:CarFactory.SetProvider(type=>{switch(type){caseA:return_container.Resolve();caseB:返回_container.Resolve();..});请注意,工厂提供者的这个示例实现使用委托,但接口也可以用作实际提供者的规范。此实现基本上是您编辑的问题中的第一个,但它没有任何特别的缺点。客户端仍然调用:varcar=newCarFactory().CreareCar(type);许多DI容器支持命名依赖项的概念。例如(结构图语法)For().Use().Named("aCar");Container.GetNamedInstance("aCar")//给你一个CarA实例如果你使用类似约定的规则如何从具体汽车类型本身派生名称,那么你有一种情况你不需要触摸当您扩展系统时,工厂不再存在。在工厂中使用它很简单。以上就是C#学习教程:工厂方法使用DI和IoC分享的全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注—classFactory(IContainerc){publicICarGetCar(stringname){Returnc.GetNamedInstance(name);}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
