Статические фабричные методы, чтобы избежать дублирования объектов

StackOverflow https://stackoverflow.com/questions/1416763

  •  06-07-2019
  •  | 
  •  

Вопрос

Я читал руководство по эффективному языку программирования Java " ;.
Он объясняет, что статические фабричные методы можно использовать, чтобы избежать ненужных дубликатов объектов .
Я не совсем понял это.
Кто-нибудь может объяснить?

Это было полезно?

Решение

Один реальный пример:

Java поддерживает как примитивные, так и объектные типы для представления байта. Когда вы конвертируете примитив в объект, вы можете сделать что-то вроде:

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

Но это создаст новый экземпляр для каждого вызова. Вместо этого вы делаете:

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

При каждом вызове метод valueOf () возвращает один и тот же экземпляр объекта Byte, представляющий значение байта 65.

После 10000 вызовов в первом примере было бы создано 10000 объектов, а во втором только один, поскольку в классе Byte есть внутренний кэш объектов Byte, представляющих все числа от -128 до 127.

Другие советы

Кажется, что все ответы о недопущении сосредоточены на одноэлементном шаблоне, который является хорошим примером не дублирования, но плохим шаблоном для использования в общем случае. На мой взгляд, данное приложение должно содержать от нуля до одного синглтона с предпочтением ноль. Однако это не имеет ничего общего с созданием ненужных объектов.

Рассмотрим вместо этого приложение, которое должно создавать множество объектов Date. Он создает так много объектов Date, что построение объектов Date отрицательно влияет на производительность. Таким образом, вместо вызова конструктора объекта Date, код подвергается рефакторингу для создания дат только посредством фабричного метода. Внутри этого фабричного метода проверяется карта, чтобы увидеть, была ли запрошенная дата уже создана. Если это так, то тот же объект возвращается с карты. В противном случае создается новый, помещается в карту и возвращается.

Что вас смущает, так это то, что, вызывая фабричный метод, вы предотвращаете создание дублированного объекта. Просто вызов метода фабрики ничего не меняет. Призыв к фабрике позволяет коду вступать во владение и принимать решение о создании объекта. При вызове нового такие решения не принимаются.

См. также этот вопрос , чтобы узнать больше понимание шаблона и для чего он может быть использован.

Когда вы вызываете конструктор, он всегда будет возвращать новый объект (если не выдается исключение). Статические фабричные методы или любая другая фабрика в этом отношении не всегда должны возвращать новый объект. Например, метод getInstance () в традиционном шаблоне проектирования Singleton является фабричным методом, который всегда возвращает один и тот же объект. Есть случаи, когда иногда вы хотите сделать что-то подобное, будь то принудительное выполнение объекта может быть создано только один раз, или создание какого-либо пула объектов и т. Д. В общем, я думаю, что это дополнительная причина для использования статические фабричные методы. Основная цель - создать псевдо-конструкторы с красивыми именами.

Вот (несколько глупый) пример использования статических фабричных методов для создания псевдо-конструкторов с хорошими именами. Рассмотрим этот класс:

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();

Это может не быть хорошим примером, но рассмотрим более сложный конструктор или конструктор с менее описательным параметром. Иногда переход к заводскому методу делает код более понятным. Есть, конечно, недостатки ...

Что касается ограничения создания объектов, рассмотрим какое-то странное ограничение, заключающееся в том, что никогда не может быть более одного генерального директора:

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

Надеюсь, эти примеры помогут.

шаблон фабричного метода может быть полезен в тех случаях, когда нет необходимости создавать новый экземпляр объекта для выполнения какого-либо действия.

Вот несколько общих случаев, которые я могу вспомнить, где может пригодиться статический фабричный метод, который возвращает тот же объект:

<Ол>
  • Создание объекта дорого . При создании объекта требуется много обработки, поэтому создание объекта более одного раза нежелательно. (Это также связано с одиночным шаблоном .)

  • У объекта нет состояния . Если между экземплярами нет различий в состоянии, то нет смысла каждый раз создавать новый объект.

  • На странице Википедии по шаблону фабричного метода есть дополнительная информация по этой теме. <Ч>

    Давайте рассмотрим конкретный пример.

    DateFormat класс использует < code> getInstance статический метод для возврата экземпляра DateFormat , который можно использовать для форматирования Date в предварительно заданное форматирование в зависимости от локали машина.

    Поскольку возвращаемое DateFormat использует одинаковое форматирование для каждого действия форматирования даты, нет реальной причины каждый раз создавать новый экземпляр DateFormat .

    Как правило, это реализуется путем создания экземпляра, если экземпляр еще не существует, и последующего сохранения ссылки на этот экземпляр. Если экземпляр нужен снова, ссылка возвращается. (Это, как правило, также реализуется шаблон Singleton.)

    Например:

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

    (К вашему сведению, приведенный выше код является примером одиночного. Кроме того, он не является потокобезопасным.)

    Если я хорошо помню, он также приводит пример в книге. Рассмотрим Decimal . Ноль довольно часто используется. Поэтому, если бы вы вызывали статический метод фабрики Decimal.valueOf (" 0 ") (не знаю, является ли это действительным API, но это не имеет значения для примера) он вернет вам экземпляр Decimal, представляющий 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
    }
    

    Обратите внимание, что существует только один экземпляр нуля, в то время как для любого другого числа создается новый объект. Кроме того, это работает с фабричными методами, а вы не можете сделать это с помощью конструкторов. Это то, на что пытался указать Блох, как преимущество для первого.

    И, как сказал Ишай, это не так тесно связано с Синглтоном. Как видите, вокруг может быть много десятичных объектов. Вместо этого вы можете использовать фабричные методы, чтобы иметь полный контроль над количеством создаваемых вами экземпляров. Вот почему это называется Фабрика.

    Мне удалось прочесть некоторые из этой книги = vcgnUi6zE-vlLUMbW3F5iRh9wTg & hl = en & ei = lGasSqTlFteJtgfd_NWwCA & sa = X & oi = book_result & ct = result & resnum = 2 # v = одна страница & q = & f = false "rel =" nofol. После прочтения того, что он написал, кажется, что он говорит о том, что статические фабричные методы дают вам больше гибкости как разработчика, и это также позволяет вам быть более ясным с тем, что возвращается. Когда вы противопоставляете это конструктору, конструктор может не обеспечить ясности в отношении того, что возвращается. Кроме того, вы можете делать такие вещи, как кэширование и т. Д. В методе static factory, который, как мне показалось, был увлекательным. Такой подход кажется хорошим, если вам нужен такой уровень контроля и гибкости.

    Смысл в том, чтобы не создавать ненужные дубликаты объектов, если вы хотите использовать кэширование. При таком подходе статической фабрики вы можете возвращать один и тот же объект при каждом вызове метода статической фабрики.

    пример:

    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