java 패턴 - 정적 팩토리 메소드 란 무엇입니까?




추상 차이 (13)

그것은 모두 유지 보수 가능성으로 귀결됩니다. 이것을 넣는 가장 좋은 방법은 new 키워드를 사용하여 객체를 만들 때마다 작성하는 코드를 구현에 연결하는 것입니다.

팩토리 패턴을 사용하면 객체로 수행하는 작업에서 객체를 만드는 방법을 분리 할 수 ​​있습니다. 생성자를 사용하여 모든 객체를 만들면 객체를 사용하는 코드를 해당 구현에 본질적으로 하드 와이어 링합니다. 개체를 사용하는 코드는 해당 개체에 "종속"됩니다. 이것은 표면적으로 큰 문제가 아닐지 모르지만, 객체가 변경되면 (생성자의 시그니처를 변경하거나 객체를 서브 클래 싱하는 것으로 생각할 때) 다시 돌아와서 모든 것을 다시 배선해야합니다.

오늘날 공장에서는 의존성 주입 (Dependency Injection)을 사용하기 위해 크게 보강되었습니다. 왜냐하면 보일러 플레이트 코드를 많이 유지해야하기 때문입니다. Dependency Injection은 기본적으로 공장과 동일하지만 객체가 구성 또는 주석을 통해 선언적으로 함께 연결되는 방법을 지정할 수 있습니다.

"정적 팩토리"메소드 란 무엇입니까?


정적 팩토리 메소드는 하나의 인스턴스 만 사용되는 구체적인 클래스를 반환하도록하려는 경우에 적합합니다.

예를 들어 데이터베이스 연결 클래스에서 하나의 클래스 만 데이터베이스 연결을 만들고 싶을 수 있습니다. 따라서 Mysql에서 Oracle로 전환하면 한 클래스의 논리를 변경할 수 있고 나머지 응용 프로그램은 새 연결을 사용하십시오.

데이터베이스 풀링을 구현하려면 응용 프로그램의 나머지 부분에 영향을주지 않고 완료해야합니다.

이 프로그램은 나머지 응용 프로그램을 공장에서 변경 한 사항으로부터 보호합니다. 이는 목적입니다.

정적 인 이유는 제한된 리소스 (소켓 연결 수 또는 파일 핸들 수)를 추적하려는 경우이 클래스가 얼마나 많은 리소스가 전달되고 반환되었는지 추적 할 수 있으므로 리소스를 고갈시키지 않아도됩니다. 제한된 자원.


팩토리 메서드는 객체의 인스턴스화를 추상화하는 메서드입니다. 일반적으로 팩토리는 인터페이스를 구현하는 클래스의 새 인스턴스가 필요하지만 구현 클래스를 모르는 경우에 유용합니다.

이것은 관련된 클래스의 계층 구조로 작업 할 때 유용합니다. 좋은 예는 GUI 툴킷입니다. 각 위젯의 구체적인 구현을 위해 생성자에 대한 호출을 간단하게 하드 코딩 할 수 있지만, 한 툴킷을 다른 툴킷으로 바꾸고 싶다면 변경해야 할 부분이 많습니다. 팩토리를 사용하면 변경할 코드의 양을 줄일 수 있습니다.


클래스의 생성자가 private 인 경우 클래스 외부의 객체를 만들 수 없습니다.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

우리는 그 클래스 외부의 객체를 만들 수 없습니다. 따라서 클래스 외부에서 x, y에 액세스 할 수 없습니다. 그렇다면이 수업의 사용법은 무엇입니까?
답은 FACTORY 입니다.
위의 클래스에 아래 메소드를 추가합니다.

public static Test getObject(){
  return new Test();
}

이제이 클래스의 외부에서이 클래스의 객체를 만들 수 있습니다. 그런데 ...

Test t = Test.getObject();

따라서 private 생성자를 실행하여 클래스의 객체를 반환하는 정적 메소드를 FACTORY 메소드라고합니다
.


자원 집약적이기 때문에 데이터베이스 연결에 대한 직접 액세스를 제공하지 않습니다. 그래서 우리는 제한보다 작은 경우 연결을 생성하는 정적 팩토리 메소드 인 getDbConnection 을 사용합니다. 그렇지 않으면, "예비"연결을 제공하려고 시도합니다. 연결이 없으면 예외가 발생합니다.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}

나는 내가 아는 것에이 글에 빛을 더할 것이라고 생각했다. 우리는 recent android project 에서이 기술을 광범위하게 사용했습니다. creating objects using new operatorcreating objects using new operator 대신 static method 를 사용하여 클래스를 인스턴스화 할 수도 있습니다. 코드 목록 :

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

정적 메서드는 조건부 개체 만들기를 지원합니다 . 생성자를 호출 할 때마다 개체가 만들어 지지만 원하지 않을 수 있습니다. 조건을 확인하기 만하면 새로운 객체를 만들고 싶다고 가정합니다. 조건이 만족되지 않으면 매번 새로운 인스턴스를 생성하지 않을 것입니다.

Effective Java 에서 가져온 또 다른 예입니다.

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

이 메소드는 boolean 프리미티브 값을 Boolean 객체 참조로 변환합니다. Boolean.valueOf(boolean) 메소드는 우리에게 객체를 생성하지 않는다는 것을 보여줍니다. 반복 static factory methods 로부터 같은 오브젝트를 돌려주는 static factory methods 의 기능에 의해, 클래스는 언제라도 존재하는 인스턴스를 엄밀하게 제어 할 수 있습니다.

Static factory methodsconstructors 와 달리 반환 subtypesubtypeobject 를 반환 할 수 있다는 점에서 다릅니다. 이러한 유연성의 한 응용 프로그램은 클래스를 공개하지 않고 개체를 반환 할 수 있다는 것입니다. 이러한 방식으로 구현 클래스를 숨기면 매우 컴팩트 한 API가됩니다.

Calendar.getInstance ()는 위의 훌륭한 예제이며, 로케일에 따라 BuddhistCalendar , JapaneseImperialCalendar 또는 기본적으로 한 Georgian 만듭니다.

내가 생각할 수있는 또 다른 예제는 Singleton pattern . 여기서 생성자를 private으로 만들면 항상 사용할 수있는 인스턴스가 하나뿐임을 확인하는 자체 getInstance 메서드를 만듭니다.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

노트! " 정적 팩토리 메소드팩토리 메소드 패턴과 동일 하지 않습니다 ."(c) Effective Java, Joshua Bloch.

팩토리 메소드 : "객체를 생성하기위한 인터페이스를 정의하지만, 인터페이스를 구현하는 클래스가 어떤 클래스를 인스턴스화할지 결정하게합니다 .Factory 메소드는 클래스가 서브 클래스"(c) GoF 로의 인스턴스 생성을 지연하도록합니다.

"정적 팩터 리 메서드는 단순히 클래스의 인스턴스를 반환하는 정적 메서드입니다." (c) 효과적인 자바, Joshua Bloch. 일반적으로이 메서드는 특정 클래스 안에 있습니다.

차이점:

정적 팩토리 메서드의 핵심 아이디어는 개체 생성을 제어하고 생성자에서 정적 메서드로 위임하는 것입니다. 생성 될 객체의 결정은 메소드 밖에서 만들어진 추상 팩터 리와 같습니다 (일반적인 경우이지만 항상 그런 것은 아닙니다). 팩토리 메소드의 핵심 (!) 개념은 팩토리 메소드 내에서 생성 할 클래스 인스턴스의 결정을 위임하는 것입니다. 예를 들어 클래식 싱글 톤 구현은 정적 팩터 리 메서드의 특별한 경우입니다. 일반적으로 사용되는 정적 팩토리 메소드의 예 :

  • valueOf
  • getInstance
  • newInstance

private 생성자가있는 정적 팩토리 메소드의 장점 중 하나는 (인스턴스 생성이 외부에서 생성되지 않도록 객체 생성이 제한되어 있어야한다는 것입니다) 인스턴스 제어 클래스를 만들 수 있다는 것입니다. 그리고 인스턴스 제어 클래스는 equals 메소드 대신 == 연산자를 사용하여 객체의 평등을 검사 할 수 있다는 것을 의미합니다 (프로그램이 실행되는 동안 a == b 인 경우에만 a.equals (b) 가 존재하지 않음) , 유효 자바에 따르면.

반복 팩토리로부터 같은 오브젝트를 돌려주는 static 팩토리 메소드의 기능에 의해, 클래스는 언제라도 존재하는 인스턴스를 엄밀하게 제어 할 수 있습니다. 이를 수행하는 클래스는 인스턴스 제어라고합니다. 인스턴스 제어 클래스를 작성해야하는 몇 가지 이유가 있습니다. 인스턴스 제어를 통해 클래스는 그것이 싱글 톤 (항목 3) 또는 인스턴스 불가능 (항목 4)임을 보장 할 수 있습니다. 또한 불변 클래스 (항목 15)가 a == b 인 경우에만 a.equals (b)가 존재하지 않는다는 것을 보증 할 수 있습니다. 클래스가이 보증을하면 클라이언트는 equals (Object) 메서드 대신 == 연산자를 사용할 수 있으므로 성능이 향상 될 수 있습니다. Enum 유형 (항목 30)은이 보증을 제공합니다.

Effective Java, Joshua Bloch (항목 1, 6 페이지)


가독성은 정적 팩토리 메소드를 사용하여 향상시킬 수 있습니다.

비교

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();

Java 구현에는 유틸리티 클래스 java.util.Arraysjava.util.Collections 가 포함되어 있습니다. 둘 다 정적 팩토리 메소드 , 예제 및 사용 방법을 포함합니다.

또한 java.lang.String 클래스에는 다음과 같은 정적 팩토리 메소드가 있습니다 .

  • String.format(...), String.valueOf(..), String.copyValueOf(...)

정적 팩토리 메소드 패턴 은 오브젝트 작성을 캡슐화하는 방법입니다. 팩토리 메소드가 없다면 Foo x = new Foo() 클래스의 constructor 직접 호출하면됩니다. 이 패턴을 사용하면 대신 factory 메소드를 호출합니다. Foo x = Foo.create() . 생성자는 private로 표시되므로 클래스 내부를 제외하고는 호출 할 수 없으며 factory 메소드는 static 으로 표시되므로 먼저 객체가 없어도 호출 할 수 있습니다.

이 패턴에는 몇 가지 장점이 있습니다. 하나는 팩토리가 여러 서브 클래스 (또는 인터페이스 구현 자) 중에서 선택하여 리턴 할 수 있다는 것입니다. 이렇게하면 호출자는 잠재적으로 복잡한 클래스 계층을 알거나 이해하지 않고도 매개 변수를 통해 원하는 동작을 지정할 수 있습니다.

또 다른 장점은 Matthew와 James가 지적한 바와 같이 연결과 같은 제한된 리소스에 대한 액세스를 제어하는 ​​것입니다. 이렇게 재사용 가능한 객체 풀 을 구현하는 방법 - 객체를 작성 , 사용 및 분해하는 대신에 비싼 프로세스 인 경우에는 한 번 빌드하고 재활용하는 것이 더 적합 할 수 있습니다. 팩토리 메서드는 기존의 사용되지 않는 인스턴스화 된 객체가 있으면 기존 객체를 반환하거나 객체 수가 일부 임계 값보다 낮 으면 객체를 생성하거나 예외를 throw하거나 상위 임계 값보다 큰 경우 null 반환 할 수 있습니다.

Wikipedia에있는 기사에 따르면 여러 팩터 방법을 사용하여 유사한 인수 유형에 대한 다른 해석을 허용합니다. 일반적으로 생성자는 클래스와 동일한 이름을 갖습니다. 즉, 지정된 signature 생성자를 하나만 가질 수 있습니다. 팩토리는 제약이 없으므로 동일한 인수 유형을 허용하는 두 가지 메소드를 가질 수 있습니다.

Coordinate c = Coordinate.createFromCartesian(double x, double y)

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

이것은 Rasmus가 지적했듯이 가독성을 향상시키는 데에도 사용할 수 있습니다.


Static 팩토리에서 유래하는 장점 중 하나는 해당 API가 클래스를 공개하지 않고 객체를 반환 할 수 있다는 것입니다. 이는 매우 컴팩트 한 API로 이어집니다. 자바에서는 Collections 클래스가 매우 작아서 32 개의 클래스를 숨기는 Collections 클래스에 의해 구현됩니다.


싱글 톤의 또 다른 장점은 쉽게 직렬화 할 수 있다는 것입니다.이 직렬화는 디스크에 상태를 저장하거나 원격으로 보낼 필요가있을 때 필요할 수 있습니다.





java design-patterns factory-method