| **Design:** Convention, **Status:** [Accepted](README.md) |
| |
| ## Favor Static Factory Methods Over Constructors |
| |
| This page describes the structures and conventions used to initialize a class. |
| |
| ### Static Factory Methods vs. Constructors |
| Static factory methods are preferable than constructors for the following reasons: |
| - Static factory methods provide meaningful names compared with constructors, which improves the readability of the codes by describing the objects being returned. |
| ```java |
| // With static factory method, giving a hint that a foobar provider with default settings is being created. |
| FoobarProvider defaultProvider = FoobarProvider.defaultFoobarProvider(); |
| |
| // With constructor |
| FoobarProvider defaultProvider = new FoobarProvider(); |
| ``` |
| - They are useful when work with immutable classes as we can reuse the same object instead of creating new object every time when it is invoked. |
| - Static factory methods can return any subtype of that class and this gives us flexibility to write a separate factory class to return different subclasses if needed. |
| |
| There are a few disadvantages of static factory methods: |
| - It might not be straightforward for the users to use static factory method to create new instances compared with constructors, but this can be improved by providing a set of common method names such as `create()` and smart IDEs such as IntelliJ and Eclipse can also give hints and help auto-completing. |
| - Classes without public or protected constructors cannot be subclassed, but this could encourage us to use composition instead of inheritance. |
| |
| In general, we should favor static factory methods over constructors. |
| |
| ### Example |
| ```java |
| public class DefaultCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable { |
| |
| private static final DefaultCredentialsProvider DEFAULT_CREDENTIALS_PROVIDER = new DefaultCredentialsProvider(builder()); |
| |
| private DefaultCredentialsProvider(Builder builder) { |
| this.providerChain = createChain(builder); |
| } |
| |
| public static DefaultCredentialsProvider create() { |
| return DEFAULT_CREDENTIALS_PROVIDER; |
| } |
| |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| public static final class Builder { |
| // ... |
| } |
| // ... |
| } |
| |
| |
| // There are two ways to create new instance |
| DefaultCredentialsProvider defaultCredentialsProvider1 = DefaultCredentialsProvider.create(); |
| DefaultCredentialsProvider defaultCredentialsProvider2 = DefaultCredentialsProvider.builder().build; |
| ``` |
| ### Naming Conventions |
| The naming conventions for the static factory methods: |
| - `create()`, `create(params)` when creating a new instance |
| eg: `DynamoDBClient.create()` |
| - `defaultXXX()` when returning an instance with default settings. |
| eg: `BackoffStrategy.defaultStrategy()` |