最佳创作设计模式

时间:2016-02-15 17:12:41

标签: java design-patterns factory builder

我正在研究一些需要抽象HttpClient创建的代码。 Http Client将是org.apache.http.client.HttpClient的一个实例。 Http客户端的配置将根据配置信息而变化(即,它是发布/获取请求,基本身份验证,可能是某些标头等)。

为了实现这一点,我考虑使用Factory设计模式来抽象Http客户端的创建;但是,我想知道Builder模式是否是更好的选择。

我已经看了几篇关于这个主题的帖子(见下文),看起来主要区别在于创建实例所需的复杂性。在下面的一篇文章中,它说工厂是构造函数的包装器,当工厂创建对象时,一切都应该在一行上完成。

问题: 1.如果HttpClient的创建需要做一些额外的步骤(即创建一个实例,设置一些参数等),我是否打破了Factory模式并应该使用构建器?

类似帖子:

  1. What is the difference between Builder Design pattern and Factory Design pattern?

  2. https://myjavalatte.wordpress.com/tag/builder-pattern-vs-factory-pattern/

  3. Difference between Abstract factory and builder?

3 个答案:

答案 0 :(得分:0)

抽象工厂模式与工厂模式不同。使用哪种模式必须取决于您工作单元的重点设计原则。

答案1:

HTTPClient处理可能非常复杂,是否使用cookie,遵循重定向,是否发送裁判,请求mimetype ...

构建器模式可以控制处理。抽象工厂模式会更好,因为:

  1. 您遵循SRP并且知道修改代码的位置。
  2. 您关注OAOO并且只有一个位置可以更改HTTPClient上的错误或优势。

答案 1 :(得分:0)

将会有很多配置可能性,因此构建器模式最适合您的问题。在一步创建时,更推荐使用工厂模式。

请注意,http-client有一个HttpClientBuilder实现:http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html

在内部,您可以混合使用这两种模式。例如:

new HttpClientBuilder()
      .setSomeParameter(MyEnum.VALUE)
      .build();

然后在构建具体的HttpBuilder时,您可以使用工厂根据 someParameter 值创建一些实例:

public void HttpClient build() {
    HttpClient client = ...
    SomeAdditionalClass instance = SomeAdditionalClassFactory.create(this.someParameter); // one-step creation
    client.setSomeAttribute(instance);
    ...
    return client;
}

答案 2 :(得分:-1)

首先,要明确这一点:没有什么比最好的设计模式更好了。只有符合您需求的设计模式和不匹配的设计模式。它总是取决于具体情况。因此,我将提供有助于识别有用模式的每种模式的描述。

解决方案1 ​​ - 构建单个实例的构建器

构建器模式用于构建具有许多不同可能配置的复杂产品。我们可以进一步划分这种模式,但是你会经常看到这些模式的混合:

表达式构建器

这种类型的Builder用于使用构建器为程序员提供一个很好的API。一个常见的例子是流体界面的实现。从本质上讲,构建器为程序员提供internal DSL

构建构建器

这种类型的Builder用于封装复杂的构造算法。与表达式构建器相反,它通常具有非常简单的界面。

解决方案2 - 构建多个实例的构建器

这是最复杂,最灵活的解决方案。它使用构建器模式来构建工厂。工厂将根据构建器的配置创建实例。因此,您可以灵活地使用构建器模式,但同时您可以从单个配置创建多个实例。

解决方案3 - 工厂

如果您只有一个配置来构建您的产品,那就去一个简单的工厂吧。仅工厂知道如何构建新实例。

解决方案4 - 抽象工厂

如果您有一组固定的配置来构建产品,则可以通过为每个配置实施新的具体工厂来使用抽象工厂模式。例如:

  • 使用基本身份验证和给定标头
  • 使用no auth且无标题

解决方案5 - 工厂方法

这与Factory和Abstract Factory模式非常相似:您有一组固定的配置。但是,与这些模式相反,您不是将每个工厂都实现为类,而是将其作为方法实现。

请注意,这与抽象工厂模式没有什么不同,因为Java 8附带了lambdas和Supplier<T>接口。这使您可以将任何工厂方法作为供应商传递给其他对象,从而有效地使其成为一个抽象工厂。

摘要

通常,构建器和工厂模式之间的区别在于,每个工厂都知道如何构建其产品。可能需要其他参数才能执行此操作。但是,可以使用单个构建器来创建具有非常不同配置的产品。将复杂构造算法封装在构建器中也是常见的做法。

那我该怎么用?

在不知道您要使用Factory / Builder的上下文的情况下,几乎不可能回答这个问题。此外,您几乎不会在实际代码中看到纯粹的模式。模式只是传达抽象设计思想的理想形式。我的意思是通常会混合不同的模式。

这方面的一个例子是构建工厂的构建器:您也可以让构建器直接构建多个产品实例,但是通过使用术语&#34; factory&#34;来更容易沟通。

此外,构造构建器和表达式构建器通常会混合在代码中,但最好将它们视为单独的概念。

Builder和Factory模式也是如此。大多数情况下,您将从一个简单的工厂方法开始。随着时间的推移,您会添加更多工厂方法此外,现有的工厂方法将变得更加复杂。在某些时候,您将开始提取工厂方法以分离Factory类。随着工厂变得越来越复杂,它慢慢变成了构建器。

实施例

DocumentBuilderFactory是如何在实际代码中使用模式的一个很好的例子:名称暗示它是一个Factory,它创建一个可以构建xml文档的Builder。让我们进一步研究:

DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(...)

DocumentBuilderFactory实际上包含两个工厂:静态方法是工厂方法,用于创建DocumentBuilderFactory类型的产品。此类的实例生成DocumentBuilder类型的产品。 DocumentBuilder的产品属于Document类型。

的DocumentBuilderFactory

现在让我们来看看哪个模式与类DocumentBuilderFactory匹配和不匹配以及为什么。首先,该类提供两个静态工厂方法来创建自身的实例。这些方法也实现了抽象工厂模式:您可以通过提供它的名称和类加载器来选择应该创建哪个混凝土工厂。

现在,我们已经完成了静态工厂方法,让我们看一下类DocumentBuilderFactory的实例。这个名字暗示这是一个工厂。实际上,正如我们上面所看到的,它是由类型DocumentBuilderFactory给出的抽象工厂接口的实现。但是,有人可能会认为这太复杂而不能成为工厂,因为它包含很多方法来传递用于创建产品的配置参数。这种类型的界面将更好地匹配表达式生成器模式。

因此,这个类是我的陈述的一个很好的例子,你经常会在实际代码中找到各种模式。毕竟,这门课只是一堂课。可以使用一组配置选项创建多个不同类型的实例的类。将它命名为众所周知的模式就是让程序员了解类正在做什么。没有更多,也没有更少。

的DocumentBuilder

对我来说,这个类可以看作是构造构建器:parse()方法执行复杂的操作,类本身有一个非常简单的接口。但是,使用newDocument()方法时它也是一个简单的工厂:它不执行复杂的操作。

同样,这是一个混合多种模式实现的类的示例。