Pergunta

Eu estava lendo Joshua Bloch " Effective Java Programming Language Guide ".
Ele explica métodos de fábrica estáticos pode ser usado para evitar objetos duplicados desnecessários .
Eu não entendi muito bem isso.
Alguém poderia explicar?

Foi útil?

Solução

Um exemplo do mundo real:

Java suporta ambos os tipos primitivos e objetos para representar um byte. Quando você converter um primitivo ao objeto que você poderia fazer algo como:

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

Bundas isso iria criar uma nova instância para cada chamada. Em vez disso você fazer:

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

Em cada chamada, o método valueOf () irá trazer o mesmo exemplo de um objecto byte representando o valor do byte 65.

Depois de 10000 chamadas 1ª exemplo teria criado 10000 objetos, enquanto o segundo apenas um, porque a classe Byte tem um cache interno de Byte objetos que representam todos os números entre -128 e 127.

Outras dicas

Todas as respostas sobre a não-duplicação parecem centrar-se sobre o padrão Singleton, que é um bom exemplo de não duplicação, mas um padrão ruim para usar no caso geral. No meu ponto de vista um determinado aplicativo deve ter zero a um singletons na mesma, com uma preferência para zero. No entanto, isso tem pouco a ver com a não criação de objetos desnecessários.

Considere vez um aplicativo que tem que fazer um monte de objetos Date. Ele está fazendo tantos objetos data que a construção dos objetos Date está a ter um efeito adverso sobre o desempenho. Então, ao invés de chamar o construtor do objeto Date, o código é reformulado para criar apenas datas através de um método de fábrica. Dentro deste método de fábrica, um mapa é verificado para ver se a data solicitada já foi criado. Se fosse, então o mesmo objeto é retornado a partir do Mapa. Caso contrário, um novo é criado, colocar no mapa e devolvido.

O que parece ser confuso você é como chamando o método de fábrica-lo a evitar a criação de um objeto duplicado. Apenas chamando um método de fábrica realmente não muda nada. O que chama a fábrica permite é para código para assumir e tomar uma decisão sobre a criação do objeto. Ao chamar nova, nenhuma dessas decisões podem ser tomadas.

Veja também esta questão para alguns mais insights sobre o padrão eo que pode ser utilizado.

Quando você invocar um construtor, ele sempre retornará um novo objeto (a menos que uma exceção é lançada). métodos de fábrica estáticos, ou qualquer tipo de fábrica para essa matéria, não tem que retornar sempre um novo objeto. Por exemplo, o método getInstance() no padrão tradicional de design Singleton é um método de fábrica que sempre retorna o mesmo objeto exato. Há casos em que às vezes você quer fazer esse tipo de coisa, se é para fazer cumprir um objeto só pode ser instanciado uma vez, ou para criar algum tipo de pool de objetos, etc. Em geral, eu acho que esta é uma razão franja para usar métodos de fábrica estático. O objetivo principal é criar bem-nomeados pseudo-construtores.

Aqui está uma (um pouco bobo) exemplo do uso de métodos de fábrica estática para fazer bem-nomeados pseudo-construtores. Considere esta classe:

class Person {

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

   ...
}

Sem métodos de fábrica estáticos, você pode fazer algo como isto:

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

Em vez disso, você pode criar métodos de fábrica estáticos:

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

   ...
}

e você pode, em vez fazer algo como isto:

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

Isto não pode ser um bom exemplo, mas considere um construtor mais complexa ou um com um parâmetro menos descritiva. Às vezes, indo a rota método de fábrica torna o código mais claro. Há, naturalmente, desvantagens ...

Quanto limitar a criação do objeto, considerar alguma restrição estranho como nunca pode haver mais do que um CEO:

class Person {

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

   public static Person newCEO() {
      return singletonCEO;
   }

   ...
}

e como ele iria ser criado:

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

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

Espero que estes exemplos de ajuda.

O método de fábrica padrão pode ser útil para momentos em que não há necessidade de criar um nova instância de um objeto, a fim de realizar alguma ação.

Aqui estão um par de casos gerais eu posso pensar de onde um método de fábrica estático que retorna o mesmo objeto pode vir a calhar:

  1. O objeto é caro para criar - Há um monte de processamento quando o objeto é instanciado, então instanciar o objeto mais de uma vez não é desejável. (Isso também está relacionado com a Singleton padrão .)

  2. O objeto mantém nenhum estado -. Se não há diferença estado entre as instâncias, não há nenhum bom propósito para criar um novo objeto de cada vez

O href="http://en.wikipedia.org/wiki/Factory_method_pattern" rel="nofollow noreferrer"> Wikipedia página tem mais informações sobre este tema.


Vamos dar uma olhada em um exemplo concreto.

O DateFormat classe usa a getInstance método estático para devolver um exemplo DateFormat, que podem ser usadas para formatar um Date em uma predefinição de formatação dependendo da localidade da máquina.

Uma vez que o DateFormat que é retornado está usando a mesma formatação para cada data formatação ação, não há nenhuma razão real para criar uma nova instância DateFormat cada vez.

Em geral, a forma como isso é implementado é criar uma instância se uma instância já não existir, em seguida, manter uma referência a essa instância. Se a instância seja necessário novamente, a referência é retornado. (Isso é geralmente como o padrão Singleton é implementado também.)

Por exemplo:

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, o código acima é um exemplo de um singleton. Além disso, não é thread-safe.)

Se eu me lembro bem, ele também dá um exemplo no livro. Considere Decimal. Zero é usado com bastante frequência. Então, se você chamaria o Decimal.valueOf("0") método de fábrica estático (não sei se esta é a API real, mas isso não importa para o propósito deste exemplo) ele irá retornar uma instância da Decimal reprezenting 0 e seria a mesma instância para qualquer chamada. A implementação seria algo como isto:

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
}

Observe que existe apenas uma única instância de zero, enquanto que para qualquer outro número um novo objeto é criado. Além disso, este trabalha com métodos de fábrica, e você não pode fazer isso com construtores. Isso é o que Bloch estava tentando salientar, como uma vantagem para o primeiro.

E, como Yishai mencionado, não é tão firmemente relacionado com Singleton. Como você pode ver, você pode ter abundância de Decimal objetos ao redor. Em vez disso, você pode usar métodos de fábrica para ter controle total sobre o número de instâncias que criar. É por isso que ele é chamado de fábrica.

Eu era capaz de ler alguns deste livro aqui . Depois de ler o que ele escreveu, parece que o que ele está dizendo é que métodos de fábrica estáticos dar-lhe mais flexibilidade como um desenvolvedor e também permite que você seja mais explícito com o que está sendo devolvido. Quando você comparar isso a um construtor o construtor não pode fornecer clareza em termos do que está sendo devolvido. Além disso, você pode fazer coisas como cache etc no método de fábrica estático que eu achei fascinante. Esta abordagem parece ser uma abordagem boa se você precisar esse nível de controle e flexibilidade.

O ponto de não criar objetos duplicados desnecessários vêm em se você quiser usar o cache. Com esta abordagem fábrica estática que poderia retornar o mesmo objeto em cada chamada para o método de fábrica estático.

Por exemplo:

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

Se você tem uma classe de fábrica para criar instâncias de objetos, cada vez que você vai criar um objeto que você vai ter que instanciar a classe de fábrica também. Basicamente, você estaria criando duplicações desta classe de fábrica.

Se for estático, você só tem a uma instância da fábrica a ser utilizado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top