É uma boa ou má idéia fazer com que os setters em java retornem "isso"?
public Employee setName(String name){
this.name = name;
return this;
}
Esse padrão pode ser útil porque você pode encadear setters como este:
list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));
em vez disso:
Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);
... mas isso vai contra a convenção padrão. Suponho que possa valer a pena apenas porque pode fazer com que o levantador faça outra coisa útil. Eu já vi esse padrão usado em alguns lugares (por exemplo, JMock, JPA), mas parece incomum e geralmente usado apenas para APIs muito bem definidas, onde esse padrão é usado em qualquer lugar.
Atualizar:
O que eu descrevi é obviamente válido, mas o que realmente estou procurando é pensar se isso geralmente é aceitável e se existem armadilhas ou práticas recomendadas relacionadas. Eu sei sobre o padrão Builder, mas ele é um pouco mais envolvido do que o que estou descrevendo - como Josh Bloch descreve, há uma classe estática associada do Builder para criação de objetos.
fonte
this
. Às vezes, até altero a função para que, em vez de retornar um valor, ela opere em um membro do objeto, apenas para que eu possa fazer isso. É maravilhoso. :)Respostas:
Não acho que exista algo especificamente errado, é apenas uma questão de estilo. É útil quando:
Alternativas para esse método podem ser:
Se você apenas definir algumas propriedades por vez, diria que não vale a pena retornar 'this'. Certamente diminui se você decidir retornar outra coisa, como um indicador de status / sucesso / mensagem.
fonte
Não é uma prática ruim. É uma prática cada vez mais comum. A maioria dos idiomas não exige que você lide com o objeto retornado, se não desejar, para que ele não mude a sintaxe de uso "normal" do setter, mas permita que você encadeie os setters.
Isso geralmente é chamado de padrão de construtor ou interface fluente .
Também é comum na API Java:
fonte
bla.foo.setBar1(...) ; bla.foo.setBar2(...)
quando você pode escreverbla.foo /* newline indented */.setBar1(...) /* underneath previous setter */ .setBar2(...)
(não é possível usar quebras de linha em um comentário do SO como este :-( ... espero que você entenda isso considerando dez desses setters ou chamadas mais complexas)Para resumir:
Alguns outros pontos não mencionados:
Isso viola o princípio de que cada função deve fazer uma (e apenas uma) coisa. Você pode ou não acreditar nisso, mas em Java eu acredito que funciona bem.
Os IDEs não vão gerá-los para você (por padrão).
Finalmente, aqui está um ponto de dados do mundo real. Eu tive problemas ao usar uma biblioteca criada assim. O construtor de consultas do Hibernate é um exemplo disso em uma biblioteca existente. Como os métodos set * da consulta estão retornando consultas, é impossível saber apenas olhando a assinatura como usá-la. Por exemplo:
Isso introduz uma ambiguidade: o método modifica o objeto atual (seu padrão) ou, talvez, a consulta seja realmente imutável (um padrão muito popular e valioso) e o método está retornando um novo. Isso apenas torna a biblioteca mais difícil de usar e muitos programadores não exploram esse recurso. Se os setters fossem setters, seria mais claro como usá-lo.
fonte
this
dificilmente é ciência complexa de foguetes. :-)Eu prefiro usar métodos 'with' para isso:
Portanto:
Aviso : essa
withX
sintaxe é comumente usada para fornecer "setters" para objetos imutáveis; portanto, os chamadores desses métodos podem esperar razoavelmente que eles criem novos objetos em vez de mutarem a instância existente. Talvez uma redação mais razoável seja algo como:Com a convenção de nomenclatura chainsetXyz (), praticamente todos devem estar felizes.
fonte
get
, umset
e umwith
para cada campo de classe. Ainda é uma solução interessante, no entanto. :)Project Lombok
's@Getter/@Setter
anotações ... isso seria fantástico para o encadeamento. Ou você pode usar algo parecido com oKestrel
combinador ( github.com/raganwald/Katy ) que os viciados em JQuery e Javascript usam.with
prefixo é uma convenção diferente. como @qualidafial deu um exemplo. Os métodos prefixados comwith
não devem retornar,this
mas uma nova instância como a instância atual, maswith
que muda. Isso é feito quando você deseja que seus objetos sejam imutáveis. Então, quando vejo um método prefixadowith
, presumo que receberei um novo objeto, não o mesmo objeto.Se você não deseja retornar
'this'
do configurador, mas não deseja usar a segunda opção, pode usar a seguinte sintaxe para definir propriedades:Como um aparte, acho que é um pouco mais limpo em C #:
fonte
equals
método. Existem maneiras muito limpas de lidar com classes anônimas,equals
se você souber o que está fazendo.Ele não apenas quebra a convenção de getters / setters, como também quebra a estrutura de referência do método Java 8.
MyClass::setMyValue
é umBiConsumer<MyClass,MyValue>
emyInstance::setMyValue
é umConsumer<MyValue>
. Se você retornar seu setterthis
, ele não será mais uma instância válidaConsumer<MyValue>
, mas sim umFunction<MyValue,MyClass>
, e fará com que qualquer coisa que use referências de método a esses setters (supondo que sejam métodos nulos) seja interrompida.fonte
Consumer<A>
eFunction<A,B>
fornecendo uma implementação padrão devoid accept(A a) { apply(a); }
. Em seguida, ele pode ser facilmente usado como um deles e não quebrará nenhum código que exija um formulário específico.Eu não sei Java, mas eu fiz isso em C ++. Outras pessoas disseram que torna as linhas muito longas e muito difíceis de ler, mas eu já fiz isso assim muitas vezes:
Isto é ainda melhor:
pelo menos eu acho. Mas não hesite em me votar e me chamar de péssimo programador, se desejar. E não sei se você pode fazer isso em Java.
fonte
//
após cada método, configurar o IDE para não unir linhas já quebradas (por exemplo, Eclipse> Propriedades> Java> Estilo de Código> Formatador> Quebra de Linha> Nunca unir linhas já quebradas).Este esquema (trocadilhos), chamado de 'interface fluente', está se tornando bastante popular agora. É aceitável, mas não é realmente minha xícara de chá.
fonte
Como ele não retorna nulo, não é mais um configurador de propriedade JavaBean válido. Isso pode importar se você é uma das sete pessoas no mundo usando ferramentas visuais "Bean Builder" ou uma das 17 usando elementos JSP-bean-setProperty.
fonte
Pelo menos em teoria , isso pode danificar os mecanismos de otimização da JVM, definindo dependências falsas entre chamadas.
Supõe-se que seja açúcar sintático, mas de fato pode criar efeitos colaterais na máquina virtual do Java 43 super-inteligente.
É por isso que eu voto não, não use.
fonte
set
método depende do primeiroset
método, embora seja conhecido pelo programador.-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining
O java7 jdk definitivamente alinha métodos encadeados e realiza o mesmo número de iterações necessárias para marcar os setters de vácuo como quentes e incorporá-los também. Parece que você subestima o poder dos algoritmos de remoção de código de operação da JVM; se souber que você está retornando isso, pulará o código de operação jrs (declaração de retorno do java) e o deixará na pilha.Não é uma prática ruim. Mas não é compatível com o JavaBeans Spec .
E há muita especificação depende desses acessadores padrão.
Você sempre pode fazê-los coexistir um com o outro.
Agora podemos usá-los juntos.
Aí vem outra versão para objeto imutável.
Agora podemos fazer isso.
fonte
some
campo. Em segundo lugar, você deve adicionar uma salvaguarda e conjuntosome
paranull
no build () assimSome
é verdadeiramente imutável, caso contrário você pode chamarbuilder.value()
na mesma instância Builder novamente. E, finalmente, sim, você tem um construtor, masSome
ainda possui um construtor público, o que significa que você não defende abertamente o uso do construtor, ou seja, o usuário não o conhece senão tentando ou procurando um método para definir um costume.value
em absoluto.Se você usar a mesma convenção em todo o aplicativo, tudo bem.
Por outro lado, se parte existente do seu aplicativo usa a convenção padrão, eu o manteria e adicionaria construtores a classes mais complicadas
fonte
Paulo Abrantes oferece outra maneira de tornar os setters JavaBean fluentes: defina uma classe de construtor interno para cada JavaBean. Se você estiver usando ferramentas que ficam confusas com setters que retornam valores, o padrão de Paulo pode ajudar.
fonte
Sou a favor de setters terem retornos "this". Eu não me importo se não é compatível com feijão. Para mim, se não há problema em ter a expressão / instrução "=", então os configuradores que retornam valores estão corretos.
fonte
Eu preferia essa abordagem, mas decidi contra.
Razões:
O padrão do Builder que vi não usa a convenção setFoo (foo) .setBar (bar), mas mais foo (foo) .bar (bar). Talvez por exatamente essas razões.
É, como sempre, uma questão de gosto. Eu apenas gosto da abordagem "menos surpresas".
fonte
Esse padrão específico é chamado de encadeamento de métodos. Link da Wikipedia , isso tem mais explicações e exemplos de como é feito em várias linguagens de programação.
PS: Apenas pensei em deixá-lo aqui, já que eu estava procurando pelo nome específico.
fonte
À primeira vista: "Medonho!".
Pensando melhor
é realmente menos propenso a erros do que
Tão interessante. Adicionando ideia à maleta de ferramentas ...
fonte
list
no início.Sim, acho que é uma boa ideia.
Se eu pudesse adicionar algo, e esse problema:
Isso funcionará:
Isso não será aceito pelo Eclipse! :
Isso ocorre porque setName () retorna um povo e não um amigo, e não há PeoplesetNickName.
Como poderíamos escrever setters para retornar a classe SELF em vez do nome da classe?
Algo assim seria bom (se a palavra-chave SELF existir). Existe mesmo assim?
fonte
class C<S extends C<S>>
, o que é mais seguro do que uma planícieS extends C
. a) SeA extends B
, eB extends C<B>
, e você tem um a, você só sabe que um B é retornado, a menos que A substitua cada método. b) Você não pode indicar um local, não brutoC<C<C<C<C<...>>>>>
.Em geral, é uma boa prática, mas pode ser necessário que as funções do tipo set usem o tipo booleano para determinar se a operação foi concluída com êxito ou não, essa também é uma maneira. Em geral, não há dogma para dizer que isso é bom ou de cama, vem da situação, é claro.
fonte
Da declaração
eu estou vendo duas coisas
1) Declaração sem sentido. 2) Falta de legibilidade.
fonte
Isso pode ser menos legível
ou isto
Isso é muito mais legível do que:
fonte
Faço meus setters há um bom tempo e o único problema real é com bibliotecas que atendem aos estritos getPropertyDescriptors para obter os acessadores de bean / escritor do bean. Nesses casos, seu "bean" java não terá os gravadores que você esperaria.
Por exemplo, eu não testei com certeza, mas não ficaria surpreso que Jackson não os reconheça como setters ao criar objetos java a partir do json / maps. Espero estar errado neste (testarei em breve).
De fato, estou desenvolvendo um ORM centralizado em SQL leve e preciso adicionar algum código além de getPropertyDescriptors a setters reconhecidos que retornem isso.
fonte
Resposta há muito tempo, mas meus dois centavos ... Está tudo bem. Eu gostaria que essa interface fluente fosse usada com mais frequência.
Repetir a variável 'factory' não adiciona mais informações abaixo:
Isso é mais limpo, imho:
Obviamente, como uma das respostas já mencionadas, a API Java teria que ser ajustada para fazer isso corretamente em algumas situações, como herança e ferramentas.
fonte
É melhor usar outras construções de idioma, se disponíveis. Por exemplo, em Kotlin, você usaria com , aplicar , ou deixe . Se você usar essa abordagem, não precisará realmente retornar uma instância do seu setter.
Essa abordagem permite que seu código de cliente seja:
Aqui estão alguns exemplos.
fonte
Se estou escrevendo uma API, uso "return this" para definir valores que serão definidos apenas uma vez. Se eu tiver outros valores que o usuário possa alterar, use um configurador de nulo padrão.
No entanto, é realmente uma questão de preferência e, em minha opinião, os setters de encadeamento parecem bem legais.
fonte
Eu concordo com todos os pôsteres afirmando que isso quebra as especificações do JavaBeans. Há razões para preservar isso, mas também sinto que o uso desse Padrão do Construtor (que foi mencionado) tem seu lugar; contanto que não seja usado em todos os lugares, deve ser aceitável. "It's Place", para mim, é onde o ponto final é uma chamada para um método "build ()".
Existem outras maneiras de definir todas essas coisas, é claro, mas a vantagem aqui é que ela evita 1) construtores públicos de muitos parâmetros e 2) objetos parcialmente especificados. Aqui, você faz o construtor coletar o que é necessário e depois chamar "build ()" no final, o que pode garantir que um objeto parcialmente especificado não seja construído, já que essa operação pode ter menos visibilidade que o público. A alternativa seria "objetos de parâmetro", mas esse IMHO apenas empurra o problema de volta a um nível.
Não gosto de construtores de muitos parâmetros porque eles tornam mais provável a passagem de muitos argumentos do mesmo tipo, o que pode facilitar a transmissão de argumentos errados para parâmetros. Não gosto de usar muitos setters porque o objeto pode ser usado antes de ser totalmente configurado. Além disso, a noção de ter valores padrão baseados em escolhas anteriores é melhor servida com o método "build ()".
Em suma, acho que é uma boa prática, se usada corretamente.
fonte
Mau hábito: um setter define um getter
que tal declarar explicitamente um método, que faz isso por U
fonte