창조 디자인 패턴 소개

1. 소개

소프트웨어 엔지니어링에서 디자인 패턴은 소프트웨어 디자인에서 가장 일반적으로 발생하는 문제에 대한 확립 된 솔루션을 설명합니다. 경험 많은 소프트웨어 개발자의 시행 착오를 통해 오랜 기간에 걸쳐 발전된 모범 사례를 나타냅니다.

Design Patterns는 Erich Gamma, John Vlissides, Ralph Johnson, Richard Helm (Gang of Four 또는 GoF라고도 함)이 1994 년에 출판 한 Design Patterns : Elements of Reusable Object-Oriented Software라는 책 이후 인기를 얻었습니다.

이 기사에서는 창조 디자인 패턴과 그 유형을 살펴볼 것입니다. 또한 일부 코드 샘플을 살펴보고 이러한 패턴이 우리의 디자인에 맞는 상황에 대해 논의 할 것입니다.

2. 창조 디자인 패턴

창조 디자인 패턴은 객체가 생성되는 방식과 관련이 있습니다. 제어 된 방식으로 개체를 생성하여 복잡성과 불안정성을 줄입니다.

가 응용 프로그램을 통해 모든 개체를 산란으로 연산자는 종종 유해한 것으로 간주됩니다. 시간이 지남에 따라 클래스가 긴밀하게 결합되기 때문에 구현을 변경하는 것이 어려울 수 있습니다.

Creational Design Patterns는 클라이언트를 실제 초기화 프로세스에서 완전히 분리하여이 문제를 해결합니다.

이 기사에서는 4 가지 유형의 Creational Design Pattern에 대해 설명합니다.

  1. Singleton – 애플리케이션 전체에 개체의 인스턴스가 최대 하나만 존재하도록합니다.
  2. Factory Method – 생성 할 정확한 객체를 지정하지 않고 여러 관련 클래스의 객체를 생성합니다.
  3. Abstract Factory – 관련 종속 개체의 패밀리를 만듭니다.
  4. Builder 단계별 접근 방식을 사용하여 복잡한 개체를 구성합니다.

이제 이러한 각 패턴에 대해 자세히 설명하겠습니다.

3. 싱글 톤 디자인 패턴

Singleton Design Pattern은 Java Virtual Machine 전체에 개체의 인스턴스가 하나만 존재하도록 하여 특정 클래스의 개체 초기화를 확인하는 것을 목표로 합니다.

Singleton 클래스는 또한 개체에 대한 하나의 고유 한 전역 액세스 지점을 제공하여 액세스 지점에 대한 각 후속 호출이 해당 특정 개체 만 반환하도록합니다.

3.1. 싱글 톤 패턴 예

싱글 톤 패턴은 GoF에 의해 도입되었지만 원래 구현은 다중 스레드 시나리오에서 문제가있는 것으로 알려져 있습니다.

따라서 여기에서는 정적 내부 클래스를 사용하는보다 최적의 접근 방식을 따를 것입니다.

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

여기에서는 Singleton 클래스 의 인스턴스를 보유 하는 정적 내부 클래스를 만들었습니다 . 외부 클래스가로드 될 때가 아니라 누군가 getInstance () 메서드를 호출 할 때만 인스턴스를 만듭니다 .

이것은 동기화가 필요하지 않고 스레드로부터 안전하며 지연 초기화를 적용하고 비교적 상용구가 적기 때문에 Singleton 클래스에 널리 사용되는 접근 방식입니다.

또한 생성자에는 개인 액세스 수정자가 있습니다. 공개 생성자는 누구나 액세스하고 새 인스턴스를 만들 수 있다는 것을 의미 하므로 Singleton을 만들기위한 요구 사항입니다 .

이것은 원래 GoF 구현이 아닙니다. 원본 버전은 Java의 Singletons에 대한 링크 된 Baeldung 기사를 참조하십시오.

3.2. 싱글 톤 디자인 패턴을 사용하는 경우

  • 생성 비용이 많이 드는 리소스 (예 : 데이터베이스 연결 개체)
  • 모든 로거를 성능을 향상시키는 싱글 톤으로 유지하는 것이 좋습니다.
  • 애플리케이션의 구성 설정에 대한 액세스를 제공하는 클래스
  • 공유 모드에서 액세스되는 리소스를 포함하는 클래스

4. 공장 방법 설계 패턴

Factory Design Pattern 또는 Factory Method Design Pattern은 Java에서 가장 많이 사용되는 디자인 패턴 중 하나입니다.

GoF에 따르면이 패턴은 "객체를 만들기위한 인터페이스를 정의하지만 하위 클래스가 인스턴스화 할 클래스를 결정하도록합니다. Factory 메서드를 사용하면 클래스가 하위 클래스에 대한 인스턴스화를 연기 할 수 있습니다.

이 패턴은 가상 생성자의 유형을 생성하여 클라이언트에서 특정 팩토리 클래스로 클래스를 초기화하는 책임을 위임합니다.

이를 위해 우리는 실제 구현 세부 사항을 숨기고 객체를 제공하는 팩토리에 의존합니다. 생성 된 개체는 공통 인터페이스를 사용하여 액세스됩니다.

4.1. 공장 방법 설계 패턴 예

이 예에서는 몇 가지 구체적인 클래스에 의해 구현 될 Polygon 인터페이스를 생성합니다 . PolygonFactory는 이 가족에서 오브젝트를 가져 오는 데 사용됩니다

먼저 Polygon 인터페이스를 만들어 보겠습니다 .

public interface Polygon { String getType(); }

다음 으로이 인터페이스를 구현하고 Polygon 유형 의 객체를 반환하는 Square , Triangle 등과 같은 몇 가지 구현을 만듭니다 .

이제 측면의 수를 인수로 취하고이 인터페이스의 적절한 구현을 반환하는 팩토리를 만들 수 있습니다.

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; } }

클라이언트가이 팩토리에 의존 하여 객체를 직접 초기화하지 않고도 적절한 Polygon 을 제공하는 방법에 주목하십시오 .

4.2. 공장 방법 설계 패턴을 사용하는 경우

  • 인터페이스 또는 추상 클래스의 구현이 자주 변경 될 것으로 예상되는 경우
  • 현재 구현이 새로운 변경 사항을 편안하게 수용 할 수없는 경우
  • 초기화 프로세스가 비교적 간단하고 생성자에 소수의 매개 변수 만 필요한 경우

5. 추상 공장 디자인 패턴

이전 섹션에서는 Factory Method 디자인 패턴을 사용하여 단일 패밀리와 관련된 객체를 만드는 방법을 보았습니다.

대조적으로 Abstract Factory Design Pattern은 관련되거나 종속 된 객체의 패밀리를 만드는 데 사용됩니다. 공장 공장이라고도합니다.

자세한 설명은 Abstract Factory 튜토리얼을 확인하십시오.

6. 빌더 디자인 패턴

Builder Design Pattern은 비교적 복잡한 개체의 구성을 다루기 위해 설계된 또 다른 창조 패턴입니다.

개체 생성의 복잡성이 증가하면 Builder 패턴은 다른 개체 (빌더)를 사용하여 개체를 구성함으로써 인스턴스화 프로세스를 분리 할 수 ​​있습니다.

이 빌더는 간단한 단계별 접근 방식을 사용하여 다른 많은 유사한 표현을 만드는 데 사용할 수 있습니다.

6.1. Builder Pattern Example

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.

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.

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

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.

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.

We've defined BankAccountBuilder in a static inner class:

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.

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

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.

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

BankAccount newAccount = new BankAccount .BankAccountBuilder("Jon", "22738022275") .withEmail("[email protected]") .wantNewsletter(true) .build();

6.2. When to Use Builder Pattern

  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

이 기사에서 우리는 자바의 창조 디자인 패턴에 대해 배웠다. 또한 Singleton, Factory Method, Abstract Factory 및 Builder Pattern의 네 가지 유형, 장점, 예제 및 사용시기에 대해 논의했습니다.

항상 그렇듯이 전체 코드 조각은 GitHub에서 사용할 수 있습니다.