Introduction to Creational Design Patterns – 创造性设计模式介绍

最后修改: 2017年 11月 22日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In software engineering, a Design Pattern describes an established solution to the most commonly encountered problems in software design. It represents the best practices evolved over a long period through trial and error by experienced software developers.

在软件工程中,设计模式描述的是软件设计中最常遇到的问题的既定解决方案。它代表了有经验的软件开发者通过长期的试验和错误而形成的最佳实践。

Design Patterns gained popularity after the book Design Patterns: Elements of Reusable Object-Oriented Software was published in 1994 by Erich Gamma, John Vlissides, Ralph Johnson, and Richard Helm (also known as Gang of Four or GoF).

设计模式在设计模式这本书后得到普及。可重复使用的面向对象软件的要素是由Erich Gamma、John Vlissides、Ralph Johnson和Richard Helm(也称为Gang of Four或GoF)于1994年出版。

In this article, we’ll explore creational design patterns and their types. We’ll also look at some code samples and discuss the situations when these patterns fit our design.

在这篇文章中,我们将探讨创造型设计模式和它们的类型。我们还将看一些代码样本,讨论这些模式适合我们设计的情况。

2. Creational Design Patterns

2.创造性的设计模式

Creational Design Patterns are concerned with the way in which objects are created. They reduce complexities and instability by creating objects in a controlled manner.

娱乐设计模式关注的是创建对象的方式。它们通过以可控的方式创建对象来减少复杂度和不稳定性。

The new operator is often considered harmful as it scatters objects all over the application. Over time it can become challenging to change an implementation because classes become tightly coupled.

new操作符通常被认为是有害的,因为它将对象分散到整个应用程序中。随着时间的推移,改变一个实现会变得很困难,因为类会变得紧密耦合。

Creational Design Patterns address this issue by decoupling the client entirely from the actual initialization process.

创造性设计模式通过将客户端与实际初始化过程完全解耦来解决这个问题。

In this article, we’ll discuss four types of Creational Design Pattern:

在这篇文章中,我们将讨论四种类型的创造型设计模式。

  1. Singleton – Ensures that at most only one instance of an object exists throughout application
  2. Factory Method – Creates objects of several related classes without specifying the exact object to be created
  3. Abstract Factory – Creates families of related dependent objects
  4. BuilderConstructs complex objects using step-by-step approach

Let’s now discuss each of these patterns in detail.

现在让我们来详细讨论这些模式中的每一个。

3. Singleton Design Pattern

3.Singleton设计模式

The Singleton Design Pattern aims to keep a check on initialization of objects of a particular class by ensuring that only one instance of the object exists throughout the Java Virtual Machine.

单子设计模式的目的是通过确保在整个Java虚拟机中只存在一个对象的实例,对特定类的对象的初始化进行检查。

A Singleton class also provides one unique global access point to the object so that each subsequent call to the access point returns only that particular object.

一个单子类还为该对象提供了一个唯一的全局访问点,以便随后对访问点的每次调用都只返回该特定对象。

3.1. Singleton Pattern Example

3.1.单子模式实例

Although the Singleton pattern was introduced by GoF, the original implementation is known to be problematic in multithreaded scenarios.

尽管Singleton模式是由GoF引入的,但众所周知,最初的实现在多线程的情况下是有问题的。

So here, we’re going to follow a more optimal approach that makes use of a static inner class:

所以在这里,我们要遵循一个更理想的方法,即利用静态的内部类。

public class Singleton  {    
    private Singleton() {}
    
    private static class SingletonHolder {    
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {    
        return SingletonHolder.instance;    
    }
}

Here, we’ve created a static inner class that holds the instance of the Singleton class. It creates the instance only when someone calls the getInstance() method and not when the outer class is loaded.

在这里,我们创建了一个静态内类,它持有Singleton类的实例。它只在有人调用getInstance()方法时创建实例,而不是在加载外层类时创建。

This is a widely used approach for a Singleton class as it doesn’t require synchronization, is thread safe, enforces lazy initialization and has comparatively less boilerplate.

这是一个被广泛使用的Singleton类的方法,因为它不需要同步,是线程安全的,强制执行懒惰的初始化,并且相对来说有较少的模板。

Also, note that the constructor has the private access modifier. This is a requirement for creating a Singleton since a public constructor would mean anyone could access it and start creating new instances.

此外,请注意,构造函数有private访问修饰符。这是创建Singleton的要求,因为public构造函数将意味着任何人都可以访问它并开始创建新的实例。

Remember, this isn’t the original GoF implementation. For the original version, please visit this linked Baeldung article on Singletons in Java.

请记住,这并不是GoF的原始实现。关于原始版本,请访问这个链接的Baeldung文章关于Java中的单子。

3.2. When to Use Singleton Design Pattern

3.2.什么时候使用Singleton设计模式

  • For resources that are expensive to create (like database connection objects)
  • It’s good practice to keep all loggers as Singletons which increases performance
  • Classes which provide access to configuration settings for the application
  • Classes that contain resources that are accessed in shared mode

4. Factory Method Design Pattern

4.工厂方法设计模式

The Factory Design Pattern or Factory Method Design Pattern is one of the most used design patterns in Java.

工厂设计模式或工厂方法设计模式是Java中最常用的设计模式之一。

According to GoF, this pattern “defines an interface for creating an object, but let subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses”.

根据GoF,这种模式“定义了一个创建对象的接口,但让子类决定实例化哪个类。工厂方法让一个类将实例化推迟到子类”。

This pattern delegates the responsibility of initializing a class from the client to a particular factory class by creating a type of virtual constructor.

这种模式通过创建一种虚拟构造函数,将初始化一个类的责任从客户端委托给一个特定的工厂类。

To achieve this, we rely on a factory which provides us with the objects, hiding the actual implementation details. The created objects are accessed using a common interface.

为了实现这一点,我们依靠一个工厂,它为我们提供对象,隐藏实际的实现细节。创建的对象使用一个通用接口进行访问。

4.1. Factory Method Design Pattern Example

4.1.工厂方法设计模式实例

In this example, we’ll create a Polygon interface which will be implemented by several concrete classes. A PolygonFactory will be used to fetch objects from this family:

在这个例子中,我们将创建一个Polygon接口,它将由几个具体的类来实现。一个PolygonFactory将被用来从这个家族中获取对象。

Factory Method Design Pattern

Let’s first create the Polygon interface:

让我们首先创建Polygon界面。

public interface Polygon {
    String getType();
}

Next, we’ll create a few implementations like Square, Triangle, etc. that implement this interface and return an object of Polygon type.

接下来,我们将创建一些实现,如Square,Triangle,等,它们实现了这个接口并返回一个Polygon类型的对象。

Now we can create a factory that takes the number of sides as an argument and returns the appropriate implementation of this interface:

现在我们可以创建一个工厂,将边的数量作为参数,并返回该接口的适当实现。

public class PolygonFactory {
    public Polygon getPolygon(int numberOfSides) {
        if(numberOfSides == 3) {
            return new Triangle();
        }
        if(numberOfSides == 4) {
            return new Square();
        }
        if(numberOfSides == 5) {
            return new Pentagon();
        }
        if(numberOfSides == 7) {
            return new Heptagon();
        }
        else if(numberOfSides == 8) {
            return new Octagon();
        }
        return null;
    }
}

Notice how the client can rely on this factory to give us an appropriate Polygon, without having to initialize the object directly.

请注意,客户端可以依靠这个工厂给我们一个合适的Polygon,而不需要直接初始化对象。

4.2. When to Use Factory Method Design Pattern

4.2.什么时候使用工厂方法设计模式

  • When the implementation of an interface or an abstract class is expected to change frequently
  • When the current implementation cannot comfortably accommodate new change
  • When the initialization process is relatively simple, and the constructor only requires a handful of parameters

5. Abstract Factory Design Pattern

5.抽象工厂设计模式

In the previous section, we saw how the Factory Method design pattern could be used to create objects related to a single family.

在上一节中,我们看到了工厂方法设计模式如何被用来创建与单一家族相关的对象。

By contrast, the Abstract Factory Design Pattern is used to create families of related or dependent objects. It’s also sometimes called a factory of factories.

相比之下,抽象工厂设计模式被用来创建相关或依赖对象的家族。它有时也被称为工厂的工厂。

For a detailed explanation, check out our Abstract Factory tutorial.

有关详细的解释,请查看我们的Abstract Factory 教程。

6. Builder Design Pattern

6.生成器设计模式

The Builder Design Pattern is another creational pattern designed to deal with the construction of comparatively complex objects.

构建者设计模式是另一种创建模式,旨在处理相对复杂的对象的构建。

When the complexity of creating object increases, the Builder pattern can separate out the instantiation process by using another object (a builder) to construct the object.

当创建对象的复杂性增加时,Builder模式可以通过使用另一个对象(一个构建器)来构建对象,从而分离出实例化过程。

This builder can then be used to create many other similar representations using a simple step-by-step approach.

然后,这个构建器可用于使用简单的逐步方法创建许多其他类似的表示。

6.1. Builder Pattern Example

6.1.构建器模式实例

The original Builder Design Pattern introduced by GoF focuses on abstraction and is very good when dealing with complex objects, however, the design is a little complicated.

GoF引入的原始Builder设计模式侧重于抽象,在处理复杂对象时非常好,然而,设计有点复杂。

Joshua Bloch, in his book Effective Java, introduced an improved version of the builder pattern which is clean, highly readable (because it makes use of fluent design) and easy to use from client’s perspective. In this example, we’ll discuss that version.

Joshua Bloch在他的《Effective Java》一书中介绍了一个改进版的构建器模式,它干净、可读性强(因为它使用了流畅的设计),而且从客户的角度来看,易于使用。在这个例子中,我们将讨论这个版本。

This example has only one class, BankAccount which contains a builder as a static inner class:

这个例子只有一个类,BankAccount,它包含一个构建器作为静态内类。

public class BankAccount {
    
    private String name;
    private String accountNumber;
    private String email;
    private boolean newsletter;

    // constructors/getters
    
    public static class BankAccountBuilder {
        // builder code
    }
}

Note that all the access modifiers on the fields are declared private since we don’t want outer objects to access them directly.

注意,所有字段上的访问修饰符都被声明为private,因为我们不希望外部对象直接访问它们。

The constructor is also private so that only the Builder assigned to this class can access it. All of the properties set in the constructor are extracted from the builder object which we supply as an argument.

构造函数也是private的,所以只有分配给这个类的Builder可以访问它。在构造函数中设置的所有属性都是从我们作为参数提供的构建器对象中提取的。

We’ve defined BankAccountBuilder in a static inner class:

我们在一个static内类中定义了BankAccountBuilder

public static class BankAccountBuilder {
    
    private String name;
    private String accountNumber;
    private String email;
    private boolean newsletter;
    
    public BankAccountBuilder(String name, String accountNumber) {
        this.name = name;
        this.accountNumber = accountNumber;
    }

    public BankAccountBuilder withEmail(String email) {
        this.email = email;
        return this;
    }

    public BankAccountBuilder wantNewsletter(boolean newsletter) {
        this.newsletter = newsletter;
        return this;
    }
    
    public BankAccount build() {
        return new BankAccount(this);
    }
}

Notice we’ve declared the same set of fields that the outer class contains. Any mandatory fields are required as arguments to the inner class’s constructor while the remaining optional fields can be specified using the setter methods.

注意我们已经声明了与外层类所包含的相同的字段集。任何强制性的字段都需要作为内层类构造函数的参数,而其余的可选字段可以使用setter方法指定。

This implementation also supports the fluent design approach by having the setter methods return the builder object.

这个实现还通过让setter方法返回构建者对象来支持流畅的设计方法。

Finally, the build method calls the private constructor of the outer class and passes itself as the argument. The returned BankAccount will be instantiated with the parameters set by the BankAccountBuilder.

最后,构建方法调用外层类的私有构造函数,并将自己作为参数传递。返回的BankAccount将被实例化,参数由BankAccountBuilder设置。

Let’s see a quick example of the builder pattern in action:

让我们看看建造者模式的一个快速实例。

BankAccount newAccount = new BankAccount
  .BankAccountBuilder("Jon", "22738022275")
  .withEmail("jon@example.com")
  .wantNewsletter(true)
  .build();

6.2. When to Use Builder Pattern

6.2.何时使用Builder模式

  1. When the process involved in creating an object is extremely complex, with lots of mandatory and optional parameters
  2. When an increase in the number of constructor parameters leads to a large list of constructors
  3. When client expects different representations for the object that’s constructed

7. Conclusion

7.结论

In this article, we learned about creational design patterns in Java. We also discussed their four different types, i.e., Singleton, Factory Method, Abstract Factory and Builder Pattern, their advantages, examples and when should we use them.

在这篇文章中,我们了解了Java中的创造型设计模式。我们还讨论了它们的四种不同类型,即单子、工厂方法、抽象工厂和生成器模式,以及它们的优点、例子和我们应该何时使用它们。

As always, the complete code snippets are available over on GitHub.

一如既往,完整的代码片段可在GitHub上获取