Pergunta

Eu estive pensando em maneiras de fornecer açúcar sintático para um quadro que tenho vindo a trabalhar. Eu quero lidar com Immitable objetos exclusivamente.

Say Eu tenho um objeto imutável e desejo de criar uma versão modificada do mesmo. Será que, na sua opinião, uma classe não-instanciável com um único princípios método pausa OO fábrica estática?


Como um exemplo usando uma string:

public final class LOWERCASE {

    private LOWERCASE() {}

    public static String string( final String STRING ) {

      return STRING.toLowerCase();
    }
}

Portanto, a partir deste exemplo que eu poderia escrever:

String lowercaseString = LOWERCASE.string( targetString );

O que eu acho muito legível.


Qualquer ressalvas contra tal abordagem?

Foi útil?

Solução

Eu não acho que é uma boa idéia para criar uma classe por método. Você poderia, em vez criar uma classe apenas métodos estáticos, chamado v.g. StringUtils e implementar os métodos. Desta forma, você chamaria:

= Cadeia lowerCaseString StringUtils.lowercase (targetString);

Isso também iria oferecer-lhe intellisense ajuda enquanto você está digitando. A lista de suas aulas vão de outra forma muito grande. Mesmo para este exemplo simples, você deve implementar mais de um aulas em minúsculas, para que você também pode atender a circunstâncias que o CulutureInfo devem ser levados em consideração.

Eu não acho que isso quebra OO princípios em qualquer forma ou que é mau design. Em outras linguagens, Ruby, por exemplo, você pode adicionar seus métodos diretamente a classe String. Métodos que terminam com! denotar que o objecto original é modificado. Todos os outros métodos retornam uma cópia modificada. Ruby on Rails adiciona alguns métodos para a classe String e há algum debate sobre se esta é uma boa técnica ou não. É definitivamente útil embora.

Outras dicas

Normalmente em objetos imutáveis, eu teria um método retornar uma versão modificada do objeto. Então se você tem alguma coleção imutável, ele pode ter um método sort (), que retorna uma nova coleção que está classificada. No entanto, no seu exemplo de Cordas isso não é possível, desde que você não pode tocar a classe String.

A sua abordagem é bastante legível, e acho que para casos extremos como este, é perfeitamente bem. Para objetos imutáveis ??que você escreve-se, eu teria o método no objeto em si.

série de Eric Lippert sobre objetos imutáveis ??em C # é muito bom, pelo caminho.

Na minha opinião, o único ponto de tal classe de fábrica seria se a classe fornecidos diferentes tipos de objetos imutáveis.

Ex:

public final class Lowercase {

  private Lowercase() {}

  public static String string( final String string ) {

   return new String( string.toLowerCase() );
  }

  public static Foo foo( final Foo f ) {
     boolean isLowerCase = true;
     return new Foo(f, isLowerCase );
  }
}

Caso contrário, você deve implementar seu método na própria classe imutável como toLowerCase () na Cadeia de classe.

De qualquer forma, eu não acho que isso quebra qualquer princípio OO.

Eu concordo com Erik. objetos imutáveis ??deve sempre ter um método retornar uma versão modificada do objeto em vez de um método estático. Há também exemplos no JDK:

  • String.substring (int)
  • BigDecimal.movePointLeft (int)

Fazendo dessa forma, tem a vantagem de que você não precisa passar a instância que pretende modificar como argumento para um método. Para as classes como string ou inteiro Eu preferiria usar uma classe wrapper. Depois, você pode controlar quando um objeto é criado (pelo construtor da classe de mensagens publicitárias ou um dos métodos da classe). Se você usar a classe Integer é muito mais complicado de controlar este como todos podem criar uma instância do mesmo.

Por outro lado, você está exemplo é considerado para algumas classes de serviços públicos como StringUtils do pacote apache commons-lang. Basta ter um olhar para isto como eu acho que você queria criar algo como isto. (Não reinventar a roda)

new String() é um cheiro de código - é quase sempre desnecessário por causa da imutabilidade de String. Uma vez que uma instância String tem um valor, essa instância nunca, nunca ter um valor diferente.

No método seguinte, new String() é redundante:

public static String string( final String string ) {
    return new String( string.toLowerCase() );
}

toLowerCase() retorna uma nova instância String (diferente) - new String() não faz nada benéfico aqui que causa uma outra criação do objeto ter o valor exato da instância String retornado por toLowerCase()

Aqui está um script pequeno Groovy que mostra o conceito (espero - nota, este é o Java sob a linguagem de script):

String a = 'CamelCase'
String b = a.toLowerCase()

println "a='${a}'"
println "b='${b}'"

produzindo

a='CamelCase'
b='camelcase'

Note que a não mudar - é imutável; b é um novo valor String.

O mesmo é verdadeiro para BigDecimal.movePointLeft() ou qualquer outro método em BigDecimal que retorna um BigDecimal -. Eles são novas instâncias, deixando a instância original inalterada

OK, agora para responder à sua pergunta:

Ter um conjunto de operações para Strings que realizam um propósito útil em sua aplicação é uma idéia bem. Usando uma fábrica, provavelmente, não é necessário para algo como String, mas pode ser para uma classe imutável diferente que leva algum esforço para construir.

No caso em que não é possível estender a classe base, como String, uma classe static methods como @kgiannakakis descrito é bom.

Caso contrário, se a classe "imutável" faz parte da aplicação, onde você tem acesso à declaração de classe / definição, métodos que retornam uma nova instância, no modelo de BigDecimal, String, etc, seria preferível. Isto é, em essência, o que @Erik Hesselink, @ de Bruno Conde e @reallyinsane disse.

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