找回密码
 会员注册
查看: 40|回复: 0

设计模式:工厂模式

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64092
发表于 2024-9-13 11:30:57 | 显示全部楼层 |阅读模式
工厂是每个开发人员都应该知道的关键创造模式之一。它们是许多高级模式的主要组成部分。很长一段时间,我在不同类型的工厂模式上遇到了麻烦。此外,在同一篇文章中很难找到有关这些类型的信息。本文介绍4种类型的工厂模式:工厂方法模式,抽象的工厂模式,静态工厂方法,简单工厂(也称为工厂)。工厂方法模式在“设计模式:可重用面向对象软件的元素”*一书中由四人帮描述。我第一次读到这个模式时,我用静态模式误解了它,这是JoshuaBloch(JavaAPI的主要架构师之一)在他的书“EffectiveJava”中描述的。简单的工厂(有时称为工厂)是非正式的,但在网上出现了很多次。最后一个,抽象的工厂模式,也在“四人帮”的书中进行了描述,并且是工厂方法模式的更广泛概念。在这篇文章中,我将解释为什么工厂是有用的,然后我将用来自著名Java框架或JavaAPI的真实示例来介绍每种类型。我将使用Java代码来实现工厂,但如果你不了解Java,你仍然能够理解这个想法。此外,我将使用UML来正式描述模式。文章目录反模式工厂需求对实例化的控制松耦合封装消除歧义工厂模式静态工厂方法真实示例日志记录框架JavaString类简单工厂工厂方法**模式**真实示例JavaAPISpring抽象工厂真实示例结论反模式虽然本文是关于工厂模式的,但仅仅为了使用模式而使用模式比从不使用模式更糟糕。这种行为是一种反模式。实际上,大多数模式使代码更难以理解。大多数时候,我不使用工厂。例如:当我在家/工作中独自编码时,我会避免使用它们。对于不会有太大变化的小项目,我也避免工厂。对于涉及多个开发人员使用相同代码的大中型项目,我发现它们很有用。我一直认为工厂是它们的优势(将在下一部分中看到它们)与代码的可读性和理解性之间的权衡。工厂的主要目标是实例化对象。但是为什么不直接使用构造函数调用创建objets呢?对于简单的用例,无需使用工厂。让我们看一下这段代码。publicclassSimpleClass{privatefinalIntegerarg1;privatefinalIntegerarg2;SimpleClass(Integerarg1,Integerarg2){this.arg1=arg1;this.arg2=arg2;}publicIntegergetArg1(){returnarg1;}publicIntegergetArg2(){returnargs;}}...publicclassBusinessClassXYZ{publicstaticvoidsomeFunction(){SimpleClassmySimpleClass=newSimpleClass(1,2);//somestuff}}123456789101112131415161718192021222324在此代码中,SimpleClass是一个非常简单的类,具有状态、无依赖项、无多态性和业务逻辑。您可以使用工厂来创建此对象,但它会使代码量增加一倍。因此,这将使代码更难以理解。**如果你能避免使用工厂来做到这一点,**你最终会得到一个更简单的代码!但是,在编写需要许多开发人员和许多代码更改的大型应用程序时,您经常会遇到更复杂的情况。对于这些复杂的案例,工厂的优势超过了它们的缺点。工厂需求现在我警告过你关于工厂的使用,让我们看看为什么它们如此强大,因此在大多数项目中使用。对实例化的控制企业应用程序的一个常见用例是限制类的实例数。您如何设法只拥有一个(或2个,或10个)类的实例,因为它消耗的资源,如套接字,数据库连接,或文件系统描述符或其他任何东西?使用构造函数方法,不同的函数(来自不同的类)很难知道类的实例是否已存在。而且,即使有一个实例,函数如何获取此实例?您可以通过使用共享变量来做到这一点,每个函数都会检查这些变量,但是它将链接所有需要实例化同一类的函数的行为,因为它们正在使用和修改相同的共享变量,代码的多个部分将具有相同的逻辑来检查类是否已经实例化,这将导致代码重复(非常糟糕!使用静态工厂方法,您可以轻松地做到这一点:publicclassSingleton{privatestaticfinalSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}...}...publicclassClassXXX{...publicstaticvoidsomeFunctionInClassXXX(){Singletoninstance=Singleton.getInstance();//somestuff}}...publicclassClassYYY{...publicstaticvoidsomeFunctionInClassYYY(){Singletoninstance=Singleton.getInstance();//somestuff}}123456789101112131415161718192021222324252627在此代码中,我们使用的工厂将类Singleton的实例数限制为1。通过限制对象的数量,我们正在创建一个实例池,而这个池模式基于工厂。注意:我们可以修改实例的创建方式(例如,通过使用原型模式而不是每次都从头开始创建新对象),而不是限制实例的数量。松耦合工厂的另一个优点是松散耦合。假设您编写了一个计算内容并需要写入日志的程序。由于这是一个很大的项目,你的一个伙伴编码,当你对业务类进行编码时,将日志写入文件系统的类(类FileSystemLogger)。如果没有工厂,您需要在使用构造函数之前使用构造函数实例化FileSystemLogger:publicclassFileSystemLogger{...publicvoidwriteLog(Strings){//Implemation}}...publicvoidsomeFunctionInClassXXX(someparameters){FileSystemLoggerlogger=newFileSystemLogger(someparamters);logger.writeLog("Thisisalog");}1234567891011但是,如果突然发生更改,并且您现在需要使用implememmentationDatabaseLogger在数据库中写入日志,会发生什么情况?如果没有工厂,则必须使用FileSystemLogger类修改所有函数。由于此记录器在任何地方都使用,因此您需要修改数百个函数/类,而使用工厂,您可以通过仅修改工厂来轻松地从一个实现切换到另一个实现://thisisanabstractionofaLoggerpublicinterfaceILogger{publicvoidwriteLog(Strings);}publicclassFileSystemLoggerimplementsILogger{...publicvoidwriteLog(Strings){//Implemation}}publicclassDatabaseLoggerimplementsILogger{...publicvoidwriteLog(Strings){//Implemation}}publicclassFactoryLogger{publicstaticILoggercreateLogger(){//youcanchoosetheloggeryouwant//aslongasit'sanILoggerreturnnewFileSystemLogger();}}somecodeusingthefactorypublicclassSomeClass{publicvoidsomeFunction(){//iftheloggerimplementationchanges//youhavenothingtochangeinthiscodeILoggerlogger=FactoryLogger.createLogger();logger.writeLog("Thisisalog");}}1234567891011121314151617181920212223242526272829303132333435如果您查看此代码,则可以轻松地将记录器实现从FileSystemLogger更改为DatabaseLogger。你只需要修改函数createLogger()(这是一个工厂)。此更改对于客户端(业务)代码是不可见的,因为客户端代码使用记录器(ILogger)的接口,并且记录器实现的选择由工厂进行。通过这样做,您可以在记录器的实现和使用记录器的代码部分之间创建松散耦合。封装有时,使用工厂可以提高代码的可读性,并通过封装降低其复杂性。假设您需要使用比较2辆车的商务级汽车比较器。这个类需要一个DatabaseConnection来获取数百万辆汽车的功能,需要一个FileSystemConnection来获取一个配置文件来参数化比较算法(例如:在油耗上增加比最大速度更多的汽油)。如果没有工厂,你可以编写如下代码:publicclassDatabaseConnection{DatabaseConnection(someparameters){//somestuff}...}publicclassFileSystemConnection{FileSystemConnection(someparameters){//somestuff}...}publicclassCarComparator{CarComparator(DatabaseConnectiondbConn,FileSystemConnectionfsConn){//somestuff}publicintcompare(Stringcar1,Stringcar2){//somestuffwithobjetsdbConnandfsConn}}...publicclassCarBusinessXY{publicvoidsomeFunctionInTheCodeThatNeedsToCompareCars(){DatabaseConnectiondb=newDatabaseConnection(someparameters);FileSystemConnectionfs=newFileSystemConnection(someparameters);CarComparatorcarComparator=newCarComparator(db,fs);carComparator.compare("FordMustang","FerrariF40");}...}publicclassCarBusinessZY{publicvoidsomeOtherFunctionInTheCodeThatNeedsToCompareCars(){DatabaseConnectiondb=newDatabaseConnection(someparameters);FileSystemConnectionfs=newFileSystemConnection(someparameters);CarComparatorcarComparator=newCarComparator(db,fs);carComparator.compare("chevroletcamaro2015","lamborghinidiablo");}...}12345678910111213141516171819202122232425262728293031323334353637383940414243此代码有效,但您可以看到,为了使用比较方法,您需要实例化数据库连接,文件系统连接,然后是汽车比较器。如果您需要在多个函数中使用比较,则必须复制代码,这意味着如果CarComparator的构造发生变化,则必须修改所有重复的部分。工厂的使用可能会使代码分解,并隐藏CarComparator类构造的复杂性。...publicclassFactory{publicstaticCarComparatorgetCarComparator(){DatabaseConnectiondb=newDatabaseConnection(someparameters);FileSystemConnectionfs=newFileSystemConnection(someparameters);CarComparatorcarComparator=newCarComparator(db,fs);}}//somecodeusingthefactorypublicclassCarBusinessXY{publicvoidsomeFunctionInTheCodeThatNeedsToCompareCars(){CarComparatorcarComparator=Factory.getCarComparator();carComparator.compare("FordMustang","FerrariF40");}...}...publicclassCarBusinessZY{publicvoidsomeOtherFunctionInTheCodeThatNeedsToCompareCars(){CarComparatorcarComparator=Factory.getCarComparator();carComparator.compare("chevroletcamaro2015","lamborghinidiablo");}...}123456789101112131415161718192021222324如果比较这两个代码,您可以看到使用工厂:减少代码行数。避免代码重复。组织代码:工厂有责任构建CarComparator,而企业级只使用它。最后一点很重要(事实上,它们都很重要!),因为这是关于关注点的分离。业务类不必知道如何构建它需要使用的复杂对象:业务类只需要关注业务问题。此外,它还增加了同一项目开发人员之间的工作分工:一个工作在CarComparator及其创建方式上。其他人则处理使用CarComparator的业务对象。消除歧义假设您有一个具有多个构造函数(具有非常不同的行为)的类。您如何确保不会错误地使用错误的构造函数?让我们看一下下面的代码:classExample{//constructoronepublicExample(doublea,floatb){//...}//constructortwopublicExample(doublea){//...}//constructorthreepublicExample(floata,doubleb){//...}}1234567891011121314虽然构造函数1和2的参数数量不同,但您很快就无法选择正确的参数,尤其是在忙碌的一天结束时,使用您喜欢的IDE中漂亮的自动完成功能(我去过那里)。更难看出构造函数1和构造函数3之间的区别。这个例子看起来像一个假的,但我在遗留代码上看到了它(真实的故事!问题是,您如何实现具有相同类型参数的不同构造函数(同时避免像构造函数一和三这样的脏方式)?以下是使用工厂的干净解决方案:classComplex{publicstaticComplexfromCartesian(doublereal,doubleimag){returnnewComplex(real,imag);}publicstaticComplexfromPolar(doublerho,doubletheta){returnnewComplex(rho*Math.cos(theta),rho*Math.sin(theta));}privateComplex(doublea,doubleb){//...}}12345678910111213在此示例中,使用工厂添加工厂方法名称对创建内容的描述:您可以从笛卡尔坐标或极坐标创建复数。在这两种情况下,您都确切地知道创作是关于什么的。工厂模式现在我们已经看到了工厂的优缺点,让我们关注不同类型的工厂模式。我将从最简单到最抽象地介绍每个工厂。如果你想使用工厂,请记住,越简单越好。静态工厂方法注意:如果您阅读了本文,并且对Java了解不多,那么静态方法就是类方法。静态工厂方法由JoshuaBloch在“EffectiveJava”中描述:“类可以提供公共静态工厂方法,该方法只是返回类实例的静态方法。换句话说,类可以提供返回实例的静态方法,而不是使用构造函数来创建实例。如果此类具有子类型,则静态工厂方法可以返回该类的类型或其子类型。虽然我讨厌UML,但我在文章的开头说过。在这里:在此图中,类ObjectWithStaticFactory有一个静态工厂方法(称为getObject())。此方法可以实例化任何类型的类ObjectWithStaticFactory,这意味着类型ObjectWithStaticFactory或类型SubType1或类型SubType2。当然,此类可以具有其他方法、属性和静态工厂方法。让我们看一下这段代码:publicclassMyClass{Integera;Integerb;MyClass(inta,intb){this.a=a;this.b=b;};publicstaticMyClassgetInstance(inta,intb){returnnewMyClass(a,b);}publicstaticvoidmain(String[]args){//instanciationwithaconstructorMyClassa=newMyClass(1,2);//instanciationwithastaticfactorymethodMyClassb=MyClass.getInstance(1,2);}}123456789101112131415161718192021此代码显示了创建MyClass实例的2种方法:MyClass中的静态工厂方法getInstance()MyClass的构造函数但这个概念可以更深入。如果具有静态工厂方法的类可以实例化另一个类,该怎么办?JoshuaBloch描述了这种可能性:“接口不能有静态方法,因此按照惯例,名为Type的接口的静态工厂方法被放在名为Types的不可检验类(Item4)中。在本例中,工厂方法getObject位于抽象类名Types中。工厂方法可以创建类Type的实例或类Type的任何子类型(图中的SubType1或SubType2)。getObject()方法可以具有参数,以便它返回给定参数的SubType1,否则返回SubType2。让我们回到Java中,假设我们有2个类:法拉利和野马,它们实现了一个接口汽车。静态工厂方法可以放在一个名为“CarFactory”的抽象类中(使用JoshuaBoch的约定,类的名称应该是“Cars”,但我不喜欢它):/theproductspublicinterfaceCar{publicvoiddrive();}publicclassMustangimplementsCar{publicvoiddrive(){//somestuff}...}publicclassFerrariimplementsCar{publicvoiddrive(){//somestuff}...}/thefactorypublicabstractclassCarFactory{publicstaticCargetCar(){//choosewhichcaryouwant}}.../somecodeusingthefactorypublicstaticvoidsomeFunctionInTheCode(){CarmyCar=CarFactory.getCar();myCar.drive();}123456789101112131415161718192021222324252627282930与其他工厂模式相比,此模式的强大之处在于您不需要为了使用它而实例化工厂(几分钟后你就会明白我的意思),实现接口的工厂(相同的注释)。它易于使用,但仅适用于提供类方法(即静态java关键字)的语言。注意:当涉及到工厂时,网络上的许多帖子都是错误的,就像这个关于stackoverflow的帖子一样,它被提高了1.5k倍。给定的工厂方法模式示例的问题在于它们是静态工厂方法。如果我引用JoshuaBloch的话:“静态工厂方法与设计模式中的工厂方法模式不同[Gamma95,p.107]。本项中描述的静态工厂方法在设计模式中没有直接的等效项。如果你看一下stackoverflow的文章,只有最后一个例子(URLStreamHandlerFactory)是GoF的工厂方法模式(我们将在几分钟内看到这个模式)真实示例下面是Java框架和JavaAPI中静态工厂方法的一些示例。在JavaAPI中查找示例非常容易,因为JoshuaBloch是许多JavaAPI的主要架构师。日志记录框架javalogging框架slf4j、logback和log4j使用抽象类LoggerFactory。如果开发人员想要写入日志,他需要从LoggerFactory的静态方法getLogger()中获取Logger的实例。getLogger()返回的Logger实现将取决于getLogger()的实现(以及getLogger()使用的开发人员编写的配置文件)。importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;publicclassExample{publicvoidexample(){//we'reusingthestaticfactorymethodtogetourloggerLoggerlogger=LoggerFactory.getLogger(Example.class);logger.info("Thisisanexample.");}}12345678910111213注意:工厂类的名称及其静态工厂方法的名称并不完全相同,无论您使用的是slf4j还是log4j还是slf4j。JavaString类Java中的String类表示一个字符串。有时,您需要从布尔值或整数中获取字符串。但是String不提供String(Integeri)或String(Booleanb)这样的构造函数。相反,它提供了多个静态工厂方法String.valueOf(…)。inti=12;StringintegerAsString=String.valueOf(i);12简单工厂这种模式不是“真实的”,但我在互联网上已经多次看到它。它没有正式的描述,但这是我的:一个简单的工厂(或工厂)是一个工具。其工作是创建/实例化对象,并且既不是工厂方法模式(我们将在后面看到此模式),也不是抽象的工厂模式(相同的注释)。你可以看到它具有静态工厂模式的泛化,但这次工厂可以被实例化(或不实例化),因为“工厂方法”不是类方法(但它可以)。对于Java开发人员来说,以非静态形式使用简单工厂是罕见的**。**因此,此模式在大多数情况下等效于静态模式。在本例中,工厂方法getObject()位于名为Factory的类中。工厂方法不是类方法,因此,您需要在使用工厂之前对其进行实例化。工厂方法可以创建类Type或其任何子类型的实例。下面是静态工厂方法的上一个示例,但这次我在使用之前先实例化了工厂/theproductspublicinterfaceCar{publicvoiddrive();}publicclassMustangimplementsCar{publicvoiddrive(){//somestuff}...}publicclassFerrariimplementsCar{publicvoiddrive(){//somestuff}...}/ThefactorypublicclassCarFactory{//thisclassisinstantiablepublicCarFactory(){//somestuff}publicCargetCar(){//choosewhichcaryouwant}}.../somecodeusingthefactorypublicstaticvoidsomeFunctionInTheCode(){CarFactorycarFactory=newCarFactory();CarmyCar=carFactory.getCar();myCar.drive();}1234567891011121314151617181920212223242526272829303132333435如您所见,这次我需要实例化工厂才能使用它。我没有在java中找到真实的例子**,因为使用静态工厂方法比使用简单的工厂更好**。不过,如果您的工厂方法需要某些实例才能工作,则可以以非静态形式使用此模式。例如,如果需要数据库连接,可以先实例化工厂(这将实例化数据库连接),然后使用需要此连接的factory方法。就个人而言,在这种情况下,我仍然会使用具有延迟初始化的静态工厂(以及数据库连接池)。告诉我,如果你知道一个Java框架,它以非静态的形式使用一个简单的工厂。工厂方法模式工厂方法模式是一个更抽象的工厂。以下是“四人帮”给出的模式定义:“定义一个用于创建对象的接口,但让子类决定要实例化的类。工厂方法允许类将实例化推迟到子类”下面是工厂方法模式的简化图:此图看起来像简单的工厂图(以非静态形式)。唯一(和BIG!)的区别是接口Factory:工厂表示“用于创建对象的接口”。它描述了一个工厂方法:getObjects()。ConcreteFactory表示“决定实例化哪个类的子类”之一。每个ConcreteFactory都有自己的工厂方法getObjects()实现。在图中,getObjects()必须返回Type(或其子类型)。这意味着一个连接器工厂可以返回子类型1,而另一个工厂可以返回子类型2。为什么使用工厂方法模式而不是简单的工厂?仅当代码需要多个工厂实现时。这将强制每个工厂具有相同的逻辑,以便使用一个实现的开发人员可以轻松切换到另一个实现,而无需徘徊如何使用它(因为他只需要调用具有相同签名的工厂方法)。由于这是抽象的,让我们回到汽车的例子。这不是一个很好的例子,但我使用它,以便你可以看到与简单工厂的区别,(我们将看到真实的例子来理解这个模式的力量):/theproductspublicinterfaceCar{publicvoiddrive();}publicclassMustangimplementsCar{publicvoiddrive(){//somestuff}...}publicclassFerrariimplementsCar{publicvoiddrive(){//somestuff}...}/thefactory//thedefinitionoftheinterfacepublicinterfaceCarFactory{publicCargetCar(){}}//therealfactorywithanimplementationofthegetCar()factorymethodpublicclassConcreteCarFactoryimplementsCarFactory{//thisclassisinstantiablepublicCarFactory(){//somestuff}publicCargetCar(){//choosewhichcaryouwantreturnnewFerrari();}}.../somecodeusingthefactorypublicstaticvoidsomeFunctionInTheCode(){CarFactorycarFactory=newConcreteCarFactory();CarmyCar=carFactory.getCar();myCar.drive();}123456789101112131415161718192021222324252627282930313233343536373839404142如果你将这段代码与简单的工厂进行比较,我这次添加了一个接口*(CarFactory)。*真正的工厂(*ConcreteCarFactory)*实现了这个接口。正如我所说,这不是一个很好的例子,因为在**此示例中,你不应该使用工厂方法模式,因为**只有一个具体的工厂。**只有当我有多个实现,如SportCarFactory,VintageCarFactory,LuxeCarFactory,CheapCarFactory…时,它才会有用。在这种情况下,开发人员可以很容易地从一个实现切换到另一个实现,因为工厂方法总是getCar()。真实示例JavaAPI在java中,一个常见的例子是集合API中的iterator()函数。每个集合都实现接口Iterable。此接口描述一个返回迭代器的函数迭代器()。ArrayList是一个集合。因此,它实现了接口Iterable及其返回迭代器//下面是java源代码中迭代器的简化定义publicinterfaceIterator{booleanhasNext();Enext();voidremove();}//工厂界面来了!publicinterfaceIterable{Iteratoriterator();}//下面是java源代码中ArrayList的简化定义//您可以看到,这个类是一个具体的工厂,它实现//afactorymethoditerator()//注意:在真正的Java源代码中,ArrayList派生自//AbstractList是实现工厂方法模式的抽象列表publicclassArrayList{//theiterator()returnsasubtypeandan"anonymous"IteratorpublicIteratoriterator(){returnnewIterator(){//implementationofthemethodshasNext(),next()andremove()}}...}12345678910111213141516171819202122232425262728这是ArrayList的标准用法importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;publicclassExample{publicstaticvoidmain(String[]ars){//instantiationofthe(concretefactory)ArrayListListmyArrayList=newArrayList();//callingthefactorymethoditerator()ofArrayListIteratormyIterator=myArrayList.iterator();}}123456789101112我展示了一个ArrayList,但我可以展示一个HashSet,一个LinkedList或一个HashMap,因为它们都是集合API的一部分。这种模式的优势在于,你不需要知道你正在使用什么类型的集合,每个集合都将通过工厂方法迭代器()提供一个迭代器。另一个很好的例子是新的Java8集合API中的stream()方法。SpringSpring框架基于工厂方法模式。ApplicationContext实现了BeanFactoryInterface。此接口描述了一个返回Object的函数ObjectgetBean(param)。这个例子很有趣,因为java中的每个类都是从Object派生的。因此,此工厂可以返回任何类的实例(取决于参数)。publicclassExample{publicstaticvoidmain(String[]args){//creationoftheBeanFactoryApplicationContextcontext=newClassPathXmlApplicationContext("config.xml");//creationtotalydifferenttypeofobjetswiththefactoryMyType1objectType1=context.getBean("myType1");MyType2objectType2=context.getBean("myType2");}}12345678910抽象工厂胖子来了!这个工厂被四人帮用下面这句话来描述:“提供一个接口,用于创建相关或依赖对象的族,而无需指定其具体类”如果你不明白这句话,不要担心这是正常的。它不是无缘无故地被称为抽象工厂!如果它能帮助你,我认为抽象的工厂模式是工厂方法模式的推广,这次工厂接口有多个相关的工厂方法。当我说相关时,我的意思是概念上的链接,以便它们形成工厂方法的“家庭”。让我们看一下图,看看与工厂方法模式的区别:Factory是一个定义多个工厂方法的接口,在我们的例子中是2:getObject1()和getObject2()。每个方法创建一个类型(或其子类型)。ConcreteFactory实现了工厂接口,因此有自己的getObject1()和getObject2()的实现。现在想象一下2个具体工厂:一个可以返回SubType1.1和SubType2.1的实例,另一个返回SubType1.2和SubType2.2的实例。由于这是非常荒谬的,让我们回到CarFactory的例子。使用工厂方法模式,工厂接口只有一个方法,getCar()。抽象工厂可以是具有3种工厂方法的接口:getEngine(),getBody()和getWheel()。您可以拥有多个混凝土工厂:SportCarFactory可以返回PoweryEngine,RaceCarBody和RacCarWheel的实例廉价汽车工厂,可以返回弱引擎,可怕的身体和烂轮的实例如果你想制造一辆跑车,你需要先加入一个SportCarFactory,然后使用它。如果你想制造一辆便宜的汽车,你需要实例化一个廉价汽车工厂,然后使用它。这个抽象工厂的3个工厂方法是相关的。它们都属于汽车生产概念。当然,工厂方法可以具有参数,以便它们返回不同的类型。例如,SportCarFactory的getEngine(String模型)工厂可以返回Ferrari458Engine或FerrariF50Engine或Ferrari450Engine或…取决于参数。这是java中的相同示例(仅使用SportCarFactory和2个工厂方法)。/thedifferentproductspublicinterfaceWheel{publicvoidturn();}publicclassRaceCarWheelimplementsWheel{publicvoidturn(){//somestuff}...}publicinterfaceEngine{publicvoidwork();}publicclassPowerfulEngineimplementsEngine{publicvoidwork(){//somestuff}...}/thefactorypublicinterfaceCarFactory{publicEnginegetEngine();publicWheelgetWheel();}publicclassSportCarFactoryimplementsCarFactory{publicEnginegetEngine(){returnnewPowerfulEngine();}publicWheelgetWheel(){returnnewRaceCarWheel();}}/somecodeusingthefactorypublicclassSomeClass{publicvoidsomeFunctionInTheCode(){CarFactorycarFactory=newSportCarFactory();WheelmyWheel=carFactory.getWheel();EnginemyEngine=carFactory.getEngine();}}123456789101112131415161718192021222324252627282930313233343536373839404142434445这个工厂并不容易。那么,什么时候应该使用它?~~从不!!!!~~嗡嗡作响,难以回答。我认为这种工厂模式是组织代码的一种方式。如果你最终在代码中有许多工厂方法模式,并且你看到一些它们之间的共同主题,你可以用一个抽象工厂收集这个组。我不是“让我们使用抽象工厂,因为我们将来可能需要一个”的忠实粉丝,因为这种模式非常抽象。我更喜欢构建简单的东西,并在需要时重构它们。然而,一个常见的用例是当您需要创建具有不同外观和感觉的用户界面时。这个例子被四人帮用来呈现这种模式。这个UI将需要一些产品,如窗口,滚动条,按钮…您可以为每种外观创建具有混凝土工厂的工厂。当然,这个例子是在互联网时代之前写的,现在你可以有一个组件,并使用CSS(或一些脚本语言)修改它的外观和感觉,即使对于桌面应用程序也是如此。这意味着静态工厂方法在大多数情况下就足够了。但是,如果您仍然想使用此模式,以下是GoF中的一些用例:“系统应配置多个产品系列之一”“你想提供一个产品的类库,你只想揭示它们的接口,而不是它们的实现”真实示例大多数DAO(数据访问对象)框架使用abtract工厂来指定具体工厂应该执行的基本操作。虽然工厂方法的名称取决于框架,但它通常关闭于:createObject(…)或persistObject(…)updateObject(…)或saveObject(…)deleteObject(…)或removeObject(…)readObject(…)或findObject(…)对于您操作的每种类型的对象,都需要一个具体的工厂。例如,如果您需要使用数据库管理人员、房屋和合同。我将有一个PersonFactory,一个HouseFactory和一个ContractFactory。来自Spring的CrudRepository是抽象工厂的一个很好的例子。如果你想要Java代码,你可以寻找JPA,Hibernate或SpringData教程。结论我希望您现在对不同类型的工厂模式以及何时使用它们有了很好的了解。虽然我在本文中说过很多次,但请记住,大多数时候工厂会使代码更加复杂/抽象。即使你知道工厂(如果你不知道,再读一遍这篇文章!),你的同事呢?然而,在处理中型/大型应用程序时,值得使用工厂。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 12:01 , Processed in 0.420351 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表