En primer lugar, felicitaciones a su elección en Java-lit: libro de Bloch es un excelente primer.
Para responder a su segunda pregunta ('a diferencia de los constructores, los métodos de fábrica estáticos no son necesarios para crear un objeto nuevo cada vez que se invocan'), es importante darse cuenta de que lo que Bloch dice es que con una fábrica estática la opción de cualquiera de los dos: devolver un nuevo objeto o devolver uno preexistente. Todo depende de lo que quieras hacer.
Por ejemplo, supongamos que tiene una clase de valor realmente simple de tipo Dinero. Su método de fábrica estático probablemente debería devolver una nueva instancia, es decir, un nuevo objeto con un valor específico para Money. Así, de esta manera:
public class Money {
private Money(String amount) { ... } /* Note the 'private'-constructor */
public static Money newInstance(String amount) {
return new Money(amount);
}
}
Pero digamos que usted tiene algún objeto que administra algún recurso y desea sincronizar el acceso a ese recurso a través de alguna clase ResourceManager. En ese caso, probablemente desee que su método de fábrica estático devuelva la misma instancia a todas las personas, lo que obligará a todos a pasar por la misma instancia, para que esa instancia 1 pueda controlar el proceso. Esto sigue el patrón singleton. Algo como esto:
public ResourceManager {
private final static ResourceManager me = new ResourceManager();
private ResourceManager() { ... } /* Note the 'private'-constructor */
public static ResourceManager getSingleton() {
return ResourceManager.me;
}
}
El método anterior obliga al usuario a sólo alguna vez ser capaz de utilizar una única instancia, lo que le permite controlar con precisión quién (y cuándo) tiene acceso a lo que sea que está administrando.
Para responder a su primera pregunta, considere esto (aunque no es el mejor ejemplo, es bastante ad-hoc):
public class Money {
private Money(String amount) { ... }
public static Money getLocalizedMoney(MoneyType localizedMoneyType, String amount) {
switch(localizedMoneyType) {
case MoneyType.US:
return new Money_US(amount);
case MoneyType.BR:
return new Money_BR(amount);
default:
return new Money_US(amount);
}
}
}
public class Money_US extends Money { ... }
public class Money_BR extends Money { ... }
Nota cómo puedo ahora hacer esto:
Money money = Money.getLocalizedMoney(user_selected_money_type);
saveLocalizedMoney(money);
Una vez más, un ejemplo realmente artificial, pero ojalá te ayude a ver más o menos a lo que estaba llegando Bloch con ese punto.
Las otras respuestas fueron buenas, creo que, como principiante, a veces es útil ver un código real.
+1 para profundizar en la práctica del diseño de software y hacer una buena pregunta. –
Gracias Brian :) – t0mcat
+1 por preguntar POR QUÉ, en lugar de simplemente hacer la programación por escrito. Hábito de un buen codificador. – TreyE