为什么我们需要工厂模式?据我了解,工厂将某个值作为输入,通过它可以确定工厂应该返回哪个类的对象。所有这些返回类都是某些超类的后代或实现一个公共接口。实际上,在工厂内部,通常的 switch case(或类似的东西)使用 new 构造函数选择要创建的对象。
这种方法有什么好处?在网上,我从工厂允许你扩展系统,允许你在一个代码中使用不同的对象等类别中找到了例子。但实际上与通常的多态性相同。那些。如果我创建一个接口或一个超类和几个继承人,那么工厂能带来什么利润?可扩展性、通用性等 提供多态性。写 factory.createClass(classType1) 而不是 new classType1 有什么好处。
工厂模式相对复杂并且有几个变体。它用于困难的情况,因此很难找到一个简洁且充分的(就有用性而言)示例。
主要思想是有几个类(具有共同的父/接口)必须创建其对象(可能具有较大的初始化逻辑)并在更远的地方使用,但它们的某些类型和参数是已知的,有些将在稍后出现. 根据该信息,创建工厂对象,将其传递到程序的其他阶段、逻辑部分。在那里,工厂已经接收到其余的参数并构建了必要的对象。也就是说,工厂用于抽象、封装、委托责任。
重要的是要注意工厂是“手动”创建的:您可以选择任何所需的工厂类型并设置它们的任何设置。在未来的管道中,工厂由对其类型一无所知的代码调用,通过单一接口以相同的方式访问所有工厂。
关于品种。当只有一个工厂类时,这称为工厂方法模式。当它们有很多并且它们继承自一个公共抽象类时,这就是“抽象工厂”模式。
假设我们正在开发一个政治行动模拟器。为此,需要政府设施。但它们依赖于意识形态和它们的一些参数(这些是工厂和它们的参数),以及模型参数(将提供给现成工厂的输入)。
在这种情况下,政府的对象将是你最终需要得到的东西(议会/总统)。工厂的角色将是类意识形态的实例,这些实例将特定于这些意识形态的一些参数作为输入。最后,所有这些都被转移到模型对象中,工厂调用带有最终参数(模拟事件的年份)的通用方法,最终的政府对象已经创建。
下面是一个 Python 中的抽象工厂的例子,有点麻烦,但就是这样使用工厂的。但是,总的来说,代码很简单:
在实际问题中,代码甚至更大,但在其中使用工厂更加合乎逻辑和有用。
顺便说一句,在 Python 中,工厂类覆盖
__call__
. 除了简洁之外,这还允许您平等地使用自己的工厂和类构造函数(毕竟,Python 类是返回最终对象的可调用对象,即类是工厂)。有用的链接:
维基百科有更多不同语言的代码示例,以及类图,这将帮助您更好地理解这些设计模式。
没有工厂模式。您可能正在撰写有关工厂方法的文章(它的另一个名称是(突然!)构造函数)。使用它的好处是你的类只知道一个构造函数接口,而不是所有可能的接口。
假设您已经描述了接口
Средство_индивидуальной_мобильности
和类Электросмокат
,并且Моноколесо
. 要制造踏板车,您需要两个轮子,一个独轮车。在您的图书馆中,Новые_правила_дорожного_движения
您不会想知道构建这些个人移动辅助设备需要多少个轮子。但是您希望能够实例化它们。怎样成为?有必要描述设计者的单一界面!这将是工厂方法模式。您接收一个方法作为输入(假设它根本不需要参数)并调用它来获取各个移动工具的实例。您根本不会想到该方法将如何创建它们,如果在 2020 年发明了飞行滑板,那么您将不需要重写您的新道路规则。很明显
фабрика.создайКласс(класТип1)
写错了。我们必须写фабрика.создайНеизвестныйМнеКлассИзвестногоМнеИнтерфейса()
。当调用的结果是指向某个抽象的指针时,这种模式使用起来很方便,实际上工厂隐藏了它创建和初始化的内容和方式,最重要的是,它不给调用代码任何关于实现的知识。
事实上,你应该对你想做的事情有一个抽象,而不是这个抽象的实现。工厂应该创建并初始化您需要的实现,并返回一个指向创建对象的抽象指针。
此外,此模式允许您在一个地方收集所有负责创建对象的代码。
经典文献中没有描述工厂模式。
GoF 书描述了抽象工厂和工厂方法。在 Internet 上,您可以找到静态工厂和简单工厂。
看起来您在询问Simple Factory。以下是它可能派上用场的一些示例。
反序列化
我们获取一个复杂对象并将其保存为例如 GeoJSON。另一方面,我们正在尝试恢复原始对象。
这里有必要
type
按属性创建不同类型的对象。该功能可由工厂接管。在具有反射支持或动态类型的语言中,这并不困难。在像 C++ 这样的语言中,您可能必须执行switch
您所写的内容。生命周期管理
当您尝试使用依赖反转做一些开箱即用的事情时,这种情况经常发生在 IoC 容器中。假设您有一个无状态的存储库对象。它可以在 IoC 中注册为单例,并且在程序执行期间将存在于单个实例中。它的每个方法都需要一个数据库连接,连接在 Web 请求开始时创建并在结束时释放。然后可以创建连接工厂或返回一个已在请求中创建的实例。以下是它在 Entity Framework 中的样子:
大量的构造函数参数
如果创建一个带有很多参数的复杂对象,代码就会变得更加复杂。经常发生不需要所有这些参数的情况。然后工厂可以向您隐藏从您的角度来看不重要的参数,自己填写。
如果在代码中根据条件创建特定类的对象,则使用简单工厂模式。如果这种情况只发生在一个地方,那么值得记住第一个SOLID原则- 单一职责(Single responsibility)并将用于创建对象的代码段移动到一个新的单独类中。如果多次 - 那么在更少的代码行中利润会更加明显(如果你有一个新的条件
if (type='d')
,那么它只需要在一个地方添加 - 在工厂中)。