É completamente contra a maneira Java de criar objetos semelhantes a estruturas?
class SomeData1 {
public int x;
public int y;
}
Eu posso ver uma classe com acessadores e mutadores mais parecidos com Java.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
A classe do primeiro exemplo é notávelmente conveniente.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Isto não é tão conveniente.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Respostas:
Este é um tópico comumente discutido. A desvantagem de criar campos públicos em objetos é que você não tem controle sobre os valores definidos para ele. Em projetos de grupo em que existem muitos programadores usando o mesmo código, é importante evitar efeitos colaterais. Além disso, às vezes é melhor retornar uma cópia do objeto do campo ou transformá-lo de alguma forma etc. Você pode zombar de tais métodos em seus testes. Se você criar uma nova classe, poderá não ver todas as ações possíveis. É como uma programação defensiva - algum dia, getters e setters podem ser úteis, e não custa muito para criar / usá-los. Então, às vezes, são úteis.
Na prática, a maioria dos campos possui getters e setters simples. Uma solução possível seria assim:
Atualização: É altamente improvável que o suporte à propriedade seja adicionado no Java 7 ou talvez nunca. Outros idiomas da JVM, como Groovy, Scala, etc, suportam esse recurso agora. - Alex Miller
fonte
=
, o que, na minha opinião, torna o código mais limpo.x
s que são duas coisas diferentes, não faz uma boa idéia. IMHO, essa é uma sugestão ruim, pois pode levar à confusão de leitores humanos. Princípio básico: não faça o leitor dar uma olhada dupla; torne óbvio o que você está dizendo - Use nomes diferentes para entidades diferentes. Mesmo que a diferença seja meramente acrescentar um sublinhado. Não confie na pontuação circundante para diferenciar as entidades.Parece que muitas pessoas Java não estão familiarizadas com as Diretrizes de codificação Sun Java, que afirmam que é bastante apropriado usar a variável de instância pública quando a classe é essencialmente uma "Struct", se o Java suportou "struct" (quando não há comportamento).
As pessoas tendem a pensar que getters e setters são o caminho do Java, como se estivessem no coração do Java. Isto não é verdade. Se você seguir as Diretrizes de codificação Java da Sun, usando variáveis de instância pública em situações apropriadas, estará realmente escrevendo um código melhor do que sobrecarregá-lo com getters e setters desnecessários.
Convenções de código Java de 1999 e ainda inalteradas.
10.1 Fornecendo acesso a variáveis de instância e classe
Não torne pública nenhuma variável de instância ou classe sem uma boa razão. Freqüentemente, as variáveis de instância não precisam ser explicitamente definidas ou obtidas, o que ocorre como efeito colateral das chamadas de método.
Um exemplo de variáveis de instância pública apropriadas é o caso em que a classe é essencialmente uma estrutura de dados, sem comportamento. Em outras palavras, se você tivesse usado uma estrutura em vez de uma classe (se Java suportasse estrutura), será apropriado tornar públicas as variáveis de instância da classe .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
fonte
Use o bom senso realmente. Se você tem algo como:
Então, não faz sentido envolvê-los em caçadores e caçadores. Você nunca vai armazenar uma coordenada x, y em pixels inteiros de qualquer outra maneira. Getters e setters apenas o atrasarão.
Por outro lado, com:
Convém alterar a maneira como um saldo é calculado em algum momento no futuro. Isso realmente deve usar getters e setters.
É sempre preferível saber por que você está aplicando boas práticas, para que você saiba quando é aceitável infringir as regras.
fonte
(-5, -5)
pode não ser uma boa ideia. :-)Para abordar questões de mutabilidade, você pode declarar x e y como finais. Por exemplo:
O código de chamada que tentar gravar nesses campos receberá um erro de tempo de compilação de "o campo x é declarado final; não pode ser atribuído".
O código do cliente pode ter a conveniência de 'mão curta' que você descreveu em sua postagem
fonte
case
expressão referente a esse campo de instância, obtiveCase expressions must be constant expressions
. qual é o caminho para contornar isso? qual é o conceito idiomático aqui?Não use
public
camposNão use
public
campos quando você realmente deseja entender o comportamento interno de uma classe. Tomejava.io.BufferedReader
por exemplo. Tem o seguinte campo:skipLF
é lido e escrito em todos os métodos de leitura. E se uma classe externa em execução em um thread separado modificasse maliciosamente o estadoskipLF
no meio de uma leitura?BufferedReader
definitivamente vai dar errado.Use
public
camposVeja esta
Point
classe, por exemplo:Isso tornaria muito difícil escrever a distância entre dois pontos.
A classe não possui nenhum comportamento além de getters e setters simples. É aceitável usar campos públicos quando a classe representa apenas uma estrutura de dados, e não possui e nunca terá comportamento (getters e setters thin não são considerados comportamento aqui). Pode ser escrito melhor desta maneira:
Limpar \ limpo!
Mas lembre-se: não apenas sua classe deve estar ausente de comportamento, mas também não deve ter motivos para ter comportamento no futuro.
(É exatamente isso que esta resposta descreve. Para citar "Convenções de código para a linguagem de programação Java: 10. Práticas de programação" :
Portanto, a documentação oficial também aceita essa prática.)
Além disso, se você tiver certeza absoluta de que os membros da
Point
classe acima devem ser imutáveis, adicione afinal
palavra-chave para aplicá-la:fonte
A propósito, a estrutura que você está dando como exemplo já existe na biblioteca de classes base Java como
java.awt.Point
. Tem x e y como campos públicos, confira você mesmo .Se você sabe o que está fazendo e outras pessoas da sua equipe sabem disso, não há problema em ter campos públicos. Mas você não deve confiar nisso, pois eles podem causar dores de cabeça, como em bugs relacionados a desenvolvedores que usam objetos como se fossem estruturas alocadas em pilha (objetos java são sempre enviados aos métodos como referências e não como cópias).
fonte
public final
campo, como na resposta de Brian, ou com um public getter, mas nenhum public setter. Ou seja, se alguém usa campos ou acessadores é irrelevante.Re: aku, izb, John Topley ...
Cuidado com os problemas de mutabilidade ...
Pode parecer sensato omitir getters / setters. Na verdade, pode estar ok em alguns casos. O verdadeiro problema com o padrão proposto mostrado aqui é a mutabilidade.
O problema é quando você passa uma referência de objeto contendo campos públicos não finais. Qualquer outra coisa com essa referência é livre para modificar esses campos. Você não tem mais controle sobre o estado desse objeto. (Pense no que aconteceria se Strings fossem mutáveis.)
Fica ruim quando esse objeto é uma parte importante do estado interno de outro, você acabou de expor a implementação interna. Para evitar isso, uma cópia do objeto deve ser retornada. Isso funciona, mas pode causar pressão maciça no GC a partir de toneladas de cópias de uso único criadas.
Se você tiver campos públicos, considere tornar a classe somente leitura. Adicione os campos como parâmetros ao construtor e marque os campos como finais. Caso contrário, verifique se você não está expondo o estado interno e, se precisar construir novas instâncias para um valor de retorno, verifique se não será chamado excessivamente.
Veja: " Java eficaz ", de Joshua Bloch - Item 13: Favor da imutabilidade.
PS: Lembre-se também de que todas as JVMs atualmente otimizam o getMethod, se possível, resultando em apenas uma única instrução de leitura de campo.
fonte
Eu tentei isso em alguns projetos, na teoria de que getters e setters confundem o código com um fragmento semanticamente sem sentido, e que outras linguagens parecem funcionar bem com ocultação de dados com base em convenções ou particionamento de responsabilidades (por exemplo, python).
Como outros observaram acima, existem 2 problemas nos quais você se depara e eles não são realmente corrigíveis:
E este é, na melhor das hipóteses, trabalhar totalmente em um projeto privado independente. Depois que você exporta tudo para uma biblioteca acessível ao público, esses problemas se tornam ainda maiores.
Java é muito detalhado, e isso é uma coisa tentadora de se fazer. Não faça isso.
fonte
Se o caminho Java é o caminho OO, sim, a criação de uma classe com campos públicos quebra os princípios em torno da ocultação de informações que dizem que um objeto deve gerenciar seu próprio estado interno. Portanto, como não estou falando apenas do jargão, um benefício da ocultação de informações é que o funcionamento interno de uma classe está oculto por trás de uma interface - digamos que você queira alterar o mecanismo pelo qual sua classe struct salvou um de seus campos, você provavelmente precisará voltar e alterar as classes que usam a classe ...)
Você também não pode tirar proveito do suporte às classes compatíveis com a nomeação JavaBean, o que prejudicará se você decidir, digamos, usar a classe em uma Página JavaServer que é escrita usando a Expression Language.
O artigo JavaWorld Por que os métodos Getter e Setter são maus também pode ser interessante para você pensar em quando não implementar métodos de acessador e mutador.
Se você está escrevendo uma solução pequena e deseja minimizar a quantidade de código envolvido, o caminho Java pode não ser o caminho certo - acho que sempre depende de você e do problema que você está tentando resolver.
fonte
Não há nada errado com esse tipo de código, desde que o autor saiba que são estruturas (ou shuttles de dados) em vez de objetos. Muitos desenvolvedores de Java não conseguem distinguir a diferença entre um objeto bem formado (não apenas uma subclasse de java.lang.Object, mas um verdadeiro objeto em um domínio específico) e um abacaxi. Logo, eles acabam escrevendo estruturas quando precisam de objetos e vice-versa.
fonte
O problema de usar o acesso ao campo público é o mesmo que usar o método novo em vez do método de fábrica - se você mudar de idéia mais tarde, todos os chamadores existentes serão interrompidos. Portanto, do ponto de vista da evolução da API, geralmente é uma boa ideia morder a bala e usar getters / setters.
Um lugar onde eu vou para o outro lado é quando você controla fortemente o acesso à classe, por exemplo, em uma classe estática interna usada como uma estrutura de dados interna. Nesse caso, pode ser muito mais claro usar o acesso ao campo.
A propósito, na afirmação da e-bartek, é altamente improvável que a IMO suporte de propriedade seja adicionado no Java 7.
fonte
Costumo usar esse padrão ao criar classes internas privadas para simplificar meu código, mas não recomendo expor esses objetos em uma API pública. Em geral, com mais freqüência você pode tornar imutáveis os objetos em sua API pública, e não é possível construir seu objeto 'semelhante a uma estrutura' de maneira imutável.
Como um aparte, mesmo se eu estivesse escrevendo esse objeto como uma classe interna privada, eu ainda forneceria um construtor para simplificar o código para inicializar o objeto. Ter que ter 3 linhas de código para obter um objeto utilizável quando se faz é apenas confuso.
fonte
Uma pergunta muito antiga, mas deixe-me fazer outra pequena contribuição. O Java 8 introduziu expressões lambda e referências a métodos. Expressões lambda podem ser simples referências de método e não declarar um corpo "verdadeiro". Mas você não pode "converter" um campo em uma referência de método. portanto
não é legal, mas
é.
fonte
data -> data.x
, que ainda é razoávelNão vejo mal se você souber que sempre será uma estrutura simples e que nunca desejará anexar um comportamento a ela.
fonte
Esta é uma pergunta sobre Design Orientado a Objetos, não sobre Java, a linguagem. Geralmente, é uma boa prática ocultar tipos de dados na classe e expor apenas os métodos que fazem parte da API da classe. Se você expuser tipos de dados internos, nunca poderá alterá-los no futuro. Se você os ocultar, sua única obrigação para com o usuário são os tipos de retorno e argumento do método.
fonte
Aqui, crio um programa para inserir Nome e Idade de 5 pessoas diferentes e realizar uma classificação (idade). Eu usei uma classe que atua como uma estrutura (como a linguagem de programação C) e uma classe principal para executar a operação completa. Abaixo estou fornecendo o código ...
O código acima é livre de erros e testado ... Basta copiá-lo e colá-lo no seu IDE e ... Você sabe e o que ??? :)
fonte
Você pode criar uma classe simples com campos públicos e sem métodos em Java, mas ainda é uma classe e ainda é tratada sintaticamente e em termos de alocação de memória, como uma classe. Não há como reproduzir genuinamente estruturas em Java.
fonte
Às vezes uso essa classe, quando preciso retornar vários valores de um método. Obviamente, esse objeto tem vida curta e visibilidade muito limitada, portanto deve estar OK.
fonte
Como na maioria das coisas, existe a regra geral e há circunstâncias específicas. Se você estiver executando um aplicativo capturado e fechado para saber como um determinado objeto será usado, poderá exercer mais liberdade para favorecer a visibilidade e / ou a eficiência. Se você estiver desenvolvendo uma classe que será usada publicamente por outras pessoas fora do seu controle, incline-se para o modelo getter / setter. Como em todas as coisas, use apenas o bom senso. Geralmente, não há problema em fazer uma rodada inicial com os públicos e depois alterá-los para getter / setters mais tarde.
fonte
A programação orientada a aspectos permite capturar atribuições ou buscar e anexar lógica interceptadora a elas, o que proponho é o caminho certo para resolver o problema. (A questão de saber se eles devem ser públicos ou protegidos ou protegidos por pacotes é ortogonal.)
Assim, você começa com campos não interceptados com o qualificador de acesso certo. À medida que os requisitos do seu programa aumentam, você anexa a lógica para talvez validar, faça uma cópia do objeto que está sendo retornado etc.
A filosofia getter / setter impõe custos a um grande número de casos simples, onde eles não são necessários.
Se o estilo do aspecto é mais limpo ou não, é um pouco qualitativo. Eu acharia fácil ver apenas as variáveis em uma classe e visualizar a lógica separadamente. De fato, a razão de ser da programação orientada a Apect é que muitas preocupações são transversais e compartimentá-las no próprio corpo da classe não é o ideal (o log é um exemplo - se você deseja registrar tudo, Java quer que você escreva um monte de getters e mantenha-os sincronizados, mas o AspectJ permite uma única linha).
A questão do IDE é um problema. Não é tanto a digitação, como a poluição visual e de leitura que surge dos get / sets.
As anotações parecem semelhantes à programação orientada a aspectos à primeira vista, no entanto, exigem que você enumere exaustivamente os cortes de ponto anexando anotações, em oposição a uma especificação concisa de corte de ponto do tipo curinga no AspectJ.
Espero que a conscientização sobre o AspectJ impeça as pessoas de optarem prematuramente por idiomas dinâmicos.
fonte