Pergunta

Qual é a prática recomendada para especificar sinalizadores em um método Java?

Já vi SWT usando int como bitfields, como:

(exemplo parcialmente de "Effective Java, 2nd Ed." página 159):

public class Text {
  public static final int STYLE_BOLD = 1 << 0; // 1
  public static final int STYLE_ITALIC = 1 << 1; // 2

  void printText(String text, int flags) {

  }
}

e sua chamada de cliente se parece com:

printText("hello", Text.STYLE_BOLD | Text.STYLE_ITALIC);

..mas isso é desencorajado, pois você pode misturar sinalizadores (valores int) de classes diferentes sem nenhuma verificação do compilador.

No mesmo livro ("Effective Java"), vejo o uso de EnumSet, mas então sua chamada de usuário se torna:

printText("hello", EnumSet.of(Style.Bold, Style.ITALIC));

Acho isso um pouco prolixo e prefiro a elegância do SWT.

Existe alguma outra alternativa ou são basicamente os dois sabores que você deve escolher?

Foi útil?

Solução

Acho que você bateu em uma parede.Não vejo outra opção.Java é detalhado, isso é um fato.Em situações como essa costumo adicionar uma variável local para tornar o código mais legível.Você consegue fazer isso,

EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.ITALIC);
printText("hello", styles);

Outras dicas

Se você quiser sinalizadores de estilo de bit, o Java os agrupa em um BitSet.Já existe há muito tempo, mas poucas pessoas se preocupam em usá-lo (preferindo incorporar o tratamento de bits no estilo C em ints).

A API do BitSet pode ser encontrada aqui.

Juntamente com algumas entradas estáticas bem escolhidas, ele funciona muito bem até você começar a verificar e definir vários bits em uma única passagem.

Aconselho que você vá com o EnumSet abordagem.

EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.Italic);

Esta abordagem fornece melhor segurança de tipo e Style ser um enum terá recursos OO completos.

Resposta tardia para quem se deparar com isso.Aqui está uma maneira de reduzir a memória e ter uma boa enumeração como a API:

public static class MyFlag {

    public static final MyFlag A = new MyFlag(1<<0);
    public static final MyFlag B = new MyFlag(1<<1);
    public static final MyFlag C = new MyFlag(1<<2);
    public static final MyFlag ALL = A.and(B).and(C);

    private final int flag;

    private MyFlag(int flag){
        this.flag = flag;
    }

    public MyFlag and(MyFlag limit){
        return new MyFlag(flag & limit.flag);
    }

    public MyFlag not(MyFlag limit){
        return new MyFlag(flag | ~limit.flag);
    }

    public boolean isSet(MyFlag limit){
        if(limit ==null){
            return false;
        }
        return (this.flag & limit.flag) != 0;
    }
}

método:

public void doFoo(MyFlag flag){
   if(MyFlag.A.isSet(flag)){
   ....
   }
   if(MyFlag.C.isSet(flag)){
   ....
   }
}

chamar:

x.doFoo(MyFlag.A.and(MyFlag.C));

Se você tiver apenas um número limitado de métodos que usarão um conjunto de estilos (como printText, no seu exemplo), você pode ajustar sua assinatura para obter um número variável de parâmetros de estilo:

void printText(String text, Style... flags) {
  EnumSet<Style> style = logicalOr(flags); // see comment below
  ...
 }

E então suas chamadas ficam muito próximas da rota do sinalizador não digitado (int):

printText("hello", Style.BOLD, Style.ITALIC);

Infelizmente, não há EnumSet.of(E... ) fábrica, apenas EnumSet.of(E first, E... more), então você precisará de um genérico logicalOr método para dividir sua matriz nos primeiros pedaços + restantes. Deixado como exercício para o leitor =).

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