method - ¿Puedo usar el patrón de construcción en un Java Enum?
method enum java (3)
Aunque no se ajusta estrictamente al patrón de construcción, la respuesta corta es sí. Una especie de
La pieza faltante no es capaz de llamar a .build()
para crear una instancia de la constante de enumeración, porque build () no puede usar la new
. Pero puede obtener algunos de los beneficios del patrón de construcción. Y seamos sinceros, no puede usar métodos de fábrica estáticos, y la subclasificación en línea de las constantes de enumeración es rara.
Aquí hay un ejemplo usando una enumeración de país.
package app;
import org.apache.commons.lang.StringUtils;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.Set;
import static app.Language.*;
import static com.google.common.base.Preconditions.*;
enum Language {
ITALIAN,
ENGLISH,
MALTESE
}
public enum Country {
ITALY(new Builder(1, "Italy").addLanguage(ITALIAN)),
MALTA(new Builder(2, "Malta").addLanguages(MALTESE, ENGLISH, ITALIAN).setPopulation(450_000));
final private int id;
final private String name;
final private Integer population;
final private Set<Language> languages;
private static class Builder {
private int id;
private String name;
private Integer population;
private Set<Language> languages = EnumSet.noneOf(Language.class);
public Builder(int id, String name) {
checkArgument(!StringUtils.isBlank(name));
this.id = id;
this.name = name;
}
public Builder setPopulation(int population) {
checkArgument(population > 0);
this.population = population;
return this;
}
public Builder addLanguage(Language language) {
checkNotNull(language);
this.languages.add(language);
return this;
}
public Builder addLanguages(Language... language) {
checkNotNull(language);
this.languages.addAll(languages);
return this;
}
}
private Country(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.population = builder.population;
this.languages = builder.languages;
checkState(!this.languages.isEmpty());
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Nullable
public Integer getPopulation() {
return population;
}
public Set<Language> getLanguages() {
return languages;
}
}
Incluso puede poner métodos estáticos de fábrica en el constructor si tiene formas comunes de construir una constante.
Así que no es del todo el constructor de Bloch, pero está bastante cerca.
Estoy reescribiendo un código, y he decidido la forma de recrear la clase, ya que hay un número fijo de hojas, las estoy creando como enumeraciones. Esta es una decisión basada en la legibilidad de un patrón de constructor frente a un constructor telescópico.
El código que tengo es que toma algunos archivos .xls, agrega encabezados (y lee algunos de otros archivos .xls) y quizás algunas subredes. A continuación, combina una variedad de estas hojas de una manera específica para hacer pestañas en un libro de Excel. Mi problema es que algunas de las pestañas del libro de trabajo que toman diferentes números de hojas son argumentos. Estoy tratando de aplicar el patrón de construcción. Este es el tipo de código que estoy tratando de escribir:
public enum workBookSheet {
mySheet1("Name1","mainSheet1.xls",true,1).addSubSheet("pathToSubSheet1.xls"),
mySheet2("Name2","mainSheet2.xls",true,2).addHeaderSheet("pathToHeaders.xls").addSubsheet("pathtoSubSheet2.xls");
private String tabName;
private String mainSheetName;
private Boolean available;
private Integer order;
private String subSheetName;
private String headerSheetName;
private workBookSheet(String tabName, String mainSheetName, Boolean available, Integer order){
this.tabName = tabName;
this.mainSheetName = mainSheetName;
this.available = available;
this.order = order;
}
public workBookSheet addSubSheet(String subSheetName){
this.subSheetName = subSheetName;
return this;
}
public workBookSheet addHeaderSheet(String headerSheetName){
this.headerSheetName = headerSheetName;
return this;
}
}
El error que me está dando Java parece estar diciendo que Java espera que mi declaración de enumeración (lista delimitada por comas de ''constructores de enumeración'' en la parte superior) solo tenga el constructor, y no métodos adicionales. Puedo mover esos métodos a un método ''constructor'' a continuación, sin queja.
public void buildSheets(){
mySheet1.addSubSheet("pathToSubSheet1.xls");
mySheet2.addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls");
}
¿Es esta la única manera de implementar un patrón de constructor en una enumeración? Requiere que ejecute un método separado, que no es demasiado complicado. Sin embargo, parece que estoy rompiendo el patrón (supongo que no es tan malo si esto funciona).
NB He echado un vistazo alrededor para ver si alguien más ha hecho esta pregunta, en SO o en otro lugar de la web. Lo más cercano que encontré fue una pregunta aquí en Enums and Factories, pero eso no responde a mi pregunta. También soy consciente de que este no es el patrón de creación, ya que no tengo una clase separada que luego acepte un método build () que cree una nueva enumeración. Supongo que esta es la raíz del problema en mi diseño inicial, pero soy relativamente nuevo en Java.
Entonces, ¿hay una mejor manera de usar un patrón de construcción en una enumeración de Java? ¿O es lo que tengo ''lo suficientemente cerca''?
Puede usar bloques de instancia (a menudo incorrectamente llamados "inicializadores de doble refuerzo") para personalizar la construcción con código arbitrario:
public enum workBookSheet {
mySheet1("Name1", "mainSheet1.xls", true, 1) {{
addSubSheet("pathToSubSheet1.xls");
}},
mySheet2("Name2", "mainSheet2.xls", true, 2) {{
// you can use the fluent interface:
addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls");
// but I would prefer coding separate statements:
addHeaderSheet("pathToHeaders.xls");
addSubSheet("pathtoSubSheet2.xls");
}};
// rest of your class the same...
}
El uso de esta sintaxis le permite solucionar las limitaciones impuestas por una enum
pero aún así tener la brevedad, la conveniencia y la flexibilidad de un patrón de construcción / fluidez.
mySheet1, mySheet2
, etc. son constantes de enumeración que siguen la sintaxis JLS definida en la sección 8.9.1
EnumConstant: Annotationsopt Identifier Argumentsopt ClassBodyopt
Por lo tanto, puede seguir la constante de enumeración mediante una lista de argumentos (los parámetros para pasar al constructor), pero no puede llamar a un método en la enumeración constante mientras lo declara. A lo sumo puedes agregar un cuerpo de clase para ello.
Además de esto, su uso del patrón de creación para crear instancias de enumeración es cuestionable, ya que, en general, el patrón de creación se utiliza cuando tiene una gran cantidad de instancias (combinaciones de valores de campo) en contraste con el concepto de enumeraciones utilizadas en algunas instancias.