문제

나는 Joshua Bloch 's를 읽고 있었다 "효과적인 Java 프로그래밍 언어 가이드".
그는 정적 공장 방법을 피하는 데 사용될 수 있다고 설명합니다. 불필요한 중복 객체.
나는 이것을 잘 이해하지 못했습니다.
누구든지 설명 할 수 있습니까?

도움이 되었습니까?

해결책

한 가지 실제 예 :

Java는 원시 및 객체 유형을 모두 지원하여 바이트를 나타냅니다. 원시를 객체로 변환하면 다음과 같은 작업을 수행 할 수 있습니다.

Byte b = new Byte( (byte) 65);

Butt 이것은 모든 통화에 대한 새 인스턴스를 만듭니다. 대신 당신은 다음과 같습니다.

Byte b = Byte.valueOf( (byte) 65);

모든 호출에서 메소드 값 ()은 바이트 값 65를 나타내는 동일한 바이트 객체의 동일한 인스턴스를 반환합니다.

10000 호출 후 첫 번째 예제는 10000 개 객체를 만들었을 것입니다. 두 번째 객체는 바이트 클래스에 -128에서 127 사이의 모든 숫자를 나타내는 바이트 객체의 내부 캐시를 갖기 때문에 두 번째 객체 만 있습니다.

다른 팁

비 생성에 대한 모든 답변은 싱글 톤 패턴에 초점을 맞추는 것으로 보이며, 이는 비 중복의 좋은 예이지만 일반적인 경우에는 사용하기에 나쁜 패턴입니다. 내 생각에 주어진 응용 프로그램에는 0에서 하나의 싱글 톤이 있어야하며 0을 선호합니다. 그러나 그것은 불필요한 객체를 만들지 않는 것과는 거의 관련이 없습니다.

대신 많은 날짜 개체를 만들어야하는 응용 프로그램을 고려하십시오. 날짜 객체의 구성이 성능에 악영향을 미치는 날짜 개체를 너무 많이 만들고 있습니다. 따라서 날짜 개체의 생성자를 호출하는 대신 코드는 공장 메소드를 통해서만 날짜 만 생성하도록 리팩토링됩니다. 이 공장 메소드 내부에서 요청 된 날짜가 이미 생성되었는지 확인하기 위해지도가 확인됩니다. 그것이 있다면, 동일한 객체가지도에서 반환됩니다. 그렇지 않으면 새 것이 생성되어지도에 넣고 반환됩니다.

당신을 혼동하는 것처럼 보이는 것은 공장 방법을 호출함으로써 중복 객체를 만드는 것을 막는 방법입니다. 공장 방법을 호출하는 것만으로도 실제로는 변경되지 않습니다. 공장에 호출 할 수있는 것은 코드를 인계하고 객체 생성에 대한 결정을 내리는 것입니다. 새로 전화 할 때 그러한 결정은 이루어질 수 없습니다.

또한보십시오 이 질문 패턴에 대한 통찰력과 사용이 무엇인지에 대한 통찰력을 얻으려면.

생성자를 호출하면 항상 새 개체를 반환합니다 (예외가 발생하지 않는 한). 정적 공장 방법 또는 그 문제에 대한 모든 종류의 공장은 항상 새로운 객체를 반환 할 필요는 없습니다. 예를 들어, getInstance() 전통적인 싱글 톤 디자인 패턴의 방법은 항상 동일한 객체를 항상 반환하는 공장 방법입니다. 객체를 한 번만 인스턴스화 할 수 있거나 객체 풀을 만들 수있는 경우에도 이런 종류의 일을하고 싶은 경우가 있습니다. 일반적으로 이것은 이것이 사용의 프린지 이유라고 생각합니다. 정적 공장 방법. 주된 목적은 이름이 좋지 않은 의사 구성자를 만드는 것입니다.

다음은 정적 공장 메소드를 사용하여 이름이 좋지 않은 의사 구성 요소를 만드는 (다소 어리석은) 예입니다. 이 수업을 고려하십시오 :

class Person {

   public Person(Role role) {
      setRole(role);
   }

   ...
}

정적 공장 방법이 없으면 다음과 같은 작업을 수행 할 수 있습니다.

Person employee = new Person(Role.EMPLOYEE);
Person manager = new Person(Role.MANAGER);

대신 정적 공장 메소드를 만들 수 있습니다.

class Person {

   public static Person newEmployee() {
      return new Person(Role.EMPLOYEE);
   }

   public static Person newManager() {
      return new Person(Role.MANAGER);
   }

   private Person(Role role) {
      setRole(role);
   }

   ...
}

대신 다음과 같은 일을 할 수 있습니다.

Person employee = Person.newEmployee();
Person manager = Person.newManager();

이것은 좋은 예는 아니지만 더 복잡한 생성자 또는 설명 매개 변수가 적은 것을 고려하십시오. 때때로 공장 방법 경로를 사용하면 코드가 더 명확 해집니다. 물론 단점이 있습니다 ...

객체 생성을 제한하는 한, 한 명 이상의 CEO와 같은 이상한 제약을 고려하십시오.

class Person {

   private static Person singletonCEO = new Person(Role.CEO);

   public static Person newCEO() {
      return singletonCEO;
   }

   ...
}

그리고 그것이 어떻게 만들어 질지 :

Person ceo1 = Person.newCEO();
Person ceo2 = Person.newCEO();

assertThat(ceo1, is(ceo2)); // JUnit 4.x

이 예가 도움이되기를 바랍니다.

그만큼 공장 방법 패턴 어떤 조치를 수행하기 위해 객체의 새 인스턴스를 만들 필요가없는 경우에 유용 할 수 있습니다.

다음은 동일한 객체를 반환하는 정적 공장 방법이 유용 할 수있는 위치에 대해 생각할 수있는 몇 가지 일반적인 경우입니다.

  1. 객체는 생성하는 데 비쌉니다 - 객체가 인스턴스화 될 때 많은 처리가 있으므로 객체를 두 번 이상 인스턴스화하는 것이 바람직하지 않습니다. (이것은 또한 관련이 있습니다 싱글 톤 패턴.)

  2. 객체는 상태를 유지하지 않습니다 - 인스턴스간에 상태 차이가 없다면 매번 새 객체를 만들기위한 좋은 목적이 없습니다.

그만큼 공장 방법 패턴의 Wikipedia 페이지 이 주제에 대한 자세한 정보가 있습니다.


구체적인 예를 살펴 보겠습니다.

그만큼 DateFormat 클래스를 사용합니다 getInstance 반환하는 정적 방법 DateFormat 인스턴스, 포맷에 사용할 수 있습니다 Date 기계의 로케일에 따라 사전 설정 형식으로.

이후 DateFormat 반환 된 것은 모든 날짜 형식 형식의 형식에 동일한 형식을 사용하고 있습니다. DateFormat 매번 인스턴스.

일반적으로,이 구현 방식은 인스턴스가 아직 존재하지 않는 경우 인스턴스를 작성한 다음 해당 인스턴스를 참조하는 것입니다. 인스턴스가 다시 필요한 경우 참조가 반환됩니다. (이것은 일반적으로 싱글 톤 패턴도 구현되는 방식입니다.)

예를 들어:

class MySingleInstanceObject {

  private MySingleInstanceObject instance;

  private MySingleInstanceObject() {
    // Initialize the object.
    // This may be expensive.
  }

  public MySingleInstanceObject getInstance() {
    if (instance == null) {
      instance = new MySingleInstanceObject();
    }

    return instance;
  }
}

(FYI, 위의 코드는 싱글 톤의 예입니다. 또한 스레드 안전이 아닙니다.)

내가 잘 기억한다면, 그는 또한 책에 모범을 보여줍니다. 고려하다 Decimal. 0은 자주 사용됩니다. 따라서 정적 공장 방법을 호출한다면 Decimal.valueOf("0")(이것이 실제 API인지 모르겠지만,이 예를 위해서는 중요하지 않습니다.) 소수점 reprezenting 0의 인스턴스를 반환하면 모든 호출과 동일한 인스턴스가됩니다. 구현은 다음과 같습니다.

public class Decimal {
    private static Decimal zero = new Decimal(0);

    public static Decimal valueOf(String s) {
        if (s.equals("0")) {
            return zero;
        } else {
            return new Decimal(parse(s)); // or whatever
        }

    // rest of the class
}

단일 인스턴스 인 인스턴스 만있는 반면 다른 숫자의 경우 새 개체가 생성됩니다. 또한 이것은 공장 방법과 함께 작동하며 생성자와 함께 할 수 없습니다. 그것이 Bloch가 전자의 이점으로 지적하려고했던 것입니다.

그리고 Yishai가 언급했듯이 싱글 톤과 밀접한 관련이 없습니다. 보시다시피, 당신은 주위에 많은 소수점 물체를 가질 수 있습니다. 대신, 공장 방법을 사용하여 생성 된 인스턴스 수를 완전히 제어 할 수 있습니다. 그것이 공장이라고 불리는 이유입니다.

이 책의 일부를 읽을 수있었습니다 여기. 그가 쓴 내용을 읽은 후에는 그가 말하는 것은 정적 공장 방법이 개발자로서 더 많은 유연성을 제공하고 반환되는 내용에 대해 더 명확하게 할 수 있다는 것입니다. 이것을 생성자와 대조 할 때 생성자는 반환되는 내용의 관점에서 명확성을 제공하지 않을 수 있습니다. 또한 내가 매혹적이라고 생각한 정적 공장 방법에서 캐싱 등과 같은 일을 할 수 있습니다. 이 접근법은 이러한 수준의 제어 및 유연성이 필요하다면 좋은 접근 방식처럼 보입니다.

캐싱을 사용하려면 불필요한 중복 객체를 생성하지 않는 요점이 들어옵니다. 이 정적 공장 접근법을 사용하면 각 호출에서 정적 공장 메소드에 동일한 객체를 반환 할 수 있습니다.

an example:

public class Person
{

   private Person(string firstName, string lastName)
   {
      this.FirstName = firstName;
      this.LastName = lastName;
   }

   public string FirstName {get; private set;}
   public string LastName {get; private set;}

   private static Dictionary<string, Person> objectPool = new Dictionary<string, Person>();
   private object lockObject = new object();

   public static Person CreatePerson(string firstName, string lastName)
   {
      var result = objectPool[firstName + lastName];
      Person person = null; 
      if (result != null)
      {
         return result
      }
      lock(lockObject)
      {
          person = new Person(firstName, lastName);
          objectPool.Add(firstName + lastName, person)
      }
      return person;
   }
}

객체 인스턴스화를 만들기위한 공장 클래스가있는 경우, 객체를 만들 때마다 공장 수업을 인스턴스화해야합니다. 기본적 으로이 공장 클래스의 복제를 만들 것입니다.

정적 인 경우 사용할 공장의 한 가지 인스턴스 만 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top