Eu li e tal, concordei e entendi os motivos pelos quais o autor sugere diminuir os getters e setters da aplicação, o que eu não entendi muito bem é como fazer isso
Alguém poderia me dar alguma dica de como evitar getters e setters?
1- Passar todos os valores das variaveis por um construtor
ou
2- deixar as variáveis como public
Eu acho que é isso…
sahusahu
rmendes08
xxta:
Acredito que só tenha 2 formas:
1- Passar todos os valores das variaveis por um construtor
ou
2- deixar as variáveis como public
Eu acho que é isso…
sahusahu
Aí é que está! Se você define métodos get/set para cada variável da sua classe, na prática acaba virando a mesma coisa que torna-lás públicas! O ideal é que o usuário de uma classe não faça nem idéia dos atributos private de uma classe, ao invés disso ele deve se concentrar no comportamento e na interface oferecida pela classe.
rmendes08
Esse trecho diz tudo!
X
xxta
na real, nao pude ler o artigo, pois aqui no trampo é bloqueado ¬¬
asaushashhus
ai só levei em consideracao o que ele falou no post…
mas qdo chegar em casa vou ler sim, parece interessante!
Eu li e tal, concordei e entendi os motivos pelos quais o autor sugere diminuir os getters e setters da aplicação, o que eu não entendi muito bem é como fazer isso
Alguém poderia me dar alguma dica de como evitar getters e setters?
Releia esta parte:
O texto não diz que acessores/modificadores são maus, o que ele diz é que violar o encapsulamento é mau.
Existe uma diferença ? Sim! E é essa diferença que vc precisa enxergar antes de perguntar como resolver o problema. O autor já lhe explica como resolver o problema.
Porque usamos acessores (getter) e modificadores (setters)?
Porque queremos isolar os atributos da classe. Não queremos que eles sejam manipulados diretamente.
Usar get/set evita que alguem manipule os dados ? Não. E esse é o problema. Vc colocou um camada à volta do atributo, mas não o isolou. O objeto externo continua podendo fazer o mesmo que fazia antes - alterar e ler qualquer atributo à vontade. Ele apenas o faz de uma forma diferente.
O mal está ai, em deixar o objeto externo controlar o estado dos atributos internos, mesmo que indiretamente.
É isso que é necessário evitar.
É obvio - o próprio autor fala disso - que em certas circunstâncias você é obrigado a ler/escreve o estado do objeto ( UI e JDBC)
Mas isso são exceções , não a regra.
E
Erick_Jeronimo
sergiotaborda
Pode crer cara, eu entendi essa parte. Mas assim, não sei se tú ou algum dos colegas aqui do fórum compartilham da minha opnião, mas salvo raras excessões, getters e setters violam o encapsulamento (pelo menos ao meu ver) :?
Principalmente porque fica complicado manter a autonomia que os objetos devem ter sobre o gerenciamento de seus estados. Já que um objeto A poderia alterar o valor de um atributo do objeto B (no caso de utilização de um setter).
Talvez eu tenha aprendido OO de forma incorreta, mas a questão é que é ligeiramente difícil pra mim conseguir “enxergar” formas de manter um design mais OO - pelo menos eu acho.
Lendo alguns desses artigos na internet eu acabei ficando inseguro com relação a práticas que eu adotava no passado e que ao meu ver eram corretas.
Concordo com o teu ponto de vista, no entanto esse é um dos outros pontos que me causam confusão…
Eu aprendi patterns tipo Façade ou Controller encapsulam regras de negócio, manipulam POJOS, delegam funções… Só que analisando melhor, acredito que eles vão contra alguns conceitos de OO - ou pelo menos a forma que eu os utilizo - porque objetos não devem ter autonomia sobre o seu estado? não devem apenas receber mensagens? Então, esses patterns acabam tirando a autonomia, e transformando objetos em objetos fantoches, ou eu estou enganado?
sergiotaborda
Primeiro temos que separar dois tipos de objetos : de dados e “os outros”. Os objetos de dados (OD para encurtar)
têm que ser carregados com os dados, certo ? não tem como fugir disso. Mas o “tem que carregar dados” é diferente de objeto tem que fornecer interface para isso. Por exemplo poderíamos usar o construtor, ou como o autor do artigo sugere ; reflection.
Mas isso seria matar uma mosca com um canhão. Os OD têm que existir e tem o seu papel ( por exemplo o padrão Memento usa algo assim). Aliás o próprio conceito de Serializable é um pouco OD.
Os outros objetos têm um estado, mas às vezes nem é um estado é uma configuração. Por exemplo a injeção de um service num outro service da vida. Isso não se qualifica como problema. Eu estou apenas canalizando as dependências.
O problema ocorre quando um objeto não controla o seu estado, quando outros objetos ficam constantemente pedindo informações e alterado informações dele. Se ele é um OD, isso não tem problema a principio.
O passo possibel é tvl imutabilizar os objetos, i.e. tirar os modificadores. Assim, mesmo que tenhamos 30 gets não ha problema, não ha violação do encaspulamento. Se tivermos que mudar alguma coisa, mude-se usando um método. A classe String é um otimo exemplo disto.
Outra opção seria criar um objeto apenas com atributos private e não criar nem get nem set para esses atributos.
Apenas quando um outro objeto necessitasse muito dessa informação poderiamos analizar como a fornecer. se por um get, ou se por um método que recebe um parametro e cospe um resultado. Inverter a responsabilidade um pouco. Desconfiar que coisas to tipo “dê-seus-dados-para-eu-fazer-algo”. Ou seja, ser critico com o design e o modelo. Que é o que o autor quer dizer com “not program blindly”. Não programar às cegas. Não usar funções do ecplise como “cria get/set automaticamente” etc…
são pequenas coisas, pequenas práticas, e não ha receita universal.
Rodrigo_Manhaes
Nem sempre. Digamos que haja um objeto imutável com uma operação public double getSome() e por qualquer motivo interno à classe este atributo tenha que passar a ser implementado com BigInteger, para continuar tendo o get teríamos que alterar a interface da classe. Ou seja, uma mudança na implementação da classe causou uma mudança em sua interface pública. Quebra de encapsulamento.
[editado]
Por sinal, gosto muito dos artigos do Holub. Ele é bastante radical em alguns pontos e isto ajuda a ampliar os horizontes.Colei uma frase dele na parede da sala onde trabalho:
[/editado]
Paulo_Silveira
Acho que o Sergio Taborda ja deixou bem claro: o problema é a quebra de encapsulamento. Nao é para nunca usar, mas tome cuidado para eles nao virarem FANTOCHES na mao dos outros objetos e servirem apenas como estruturinha de dados.
Eu escrevi um artigo sobre esse assunto:
Tambem concordo com o Sergio sobre a imutabilidade: classes imutaveis sao simples, faceis de dar manutencao, thread safe e elegantes. Santo Bloch ja dizia faz tempo…
sergiotaborda
Nem sempre. Digamos que haja um objeto imutável com uma operação public double getSome() e por qualquer motivo interno à classe este atributo tenha que passar a ser implementado com BigInteger, para continuar tendo o get teríamos que alterar a interface da classe. Ou seja, uma mudança na implementação da classe causou uma mudança em sua interface pública. Quebra de encapsulamento.
Esse é exactamente o tipo de pensamento que destroi o encapsulamento. Se a sua classe passou a ser implementado com BigDecimal não tem porque mudar o retorno do método.
Se vc se enganou ao criar um método com double que deveria ter a exatidão de BigDecimal e ainda vai a tempo de alterar faça um simples refractoring da classe. Se a classe já está em produção marque o método como deprecated, explique que ele não têm a exatidão necessária e que o método getSomeBigger deve ser usado em vez. Explique que o método getSome será retirado da API na versão x.y.z. O método getSomeBigger é um método novo. O método getSome permanece inalterado.
Paulo_Silveira
Perfeito! Basta refatorar. Mudancas na representacao interna/implementacao NAO devem surtir efeito na interface
e adicione o getter pra bigdecimal se necessario/conveniente.
Rodrigo_Manhaes
sergiotaborda:
Esse é exactamente o tipo de pensamento que destroi o encapsulamento. Se a sua classe passou a ser implementado com BigDecimal não tem porque mudar o retorno do método.
Se vc se enganou ao criar um método com double que deveria ter a exatidão de BigDecimal e ainda vai a tempo de alterar faça um simples refractoring da classe. Se a classe já está em produção marque o método como deprecated, explique que ele não têm a exatidão necessária e que o método getSomeBigger deve ser usado em vez. Explique que o método getSome será retirado da API na versão x.y.z. O método getSomeBigger é um método novo. O método getSome permanece inalterado.
Este “tipo de pensamento” - e vejo que os ânimos andam meio exaltados por este fórum - foi apenas um exemplo de que assumir de modo naïve que basta ter um objeto imutável e está tudo encapsulado pode não ser bem assim. Quanto ao recurso do deprecated, sim, é uma boa solução para a questão. Mas a solução final para este tipo de problema - se exatidão numérica for importante para o modelo - é um pattern como o Money do PoEAA.
rponte
Infelizmente somos obrigados a colocar getters e setters nas nossas classes somente para satisfazer algum framework MVC que se utiliza da especificação JavaBeans. Porém não é só porque temos estes métodos que devemos utiliza-los quando estivermos trabalhando na camada de negócios.
Mas enfim, alguém conhece algum framework MVC que não te obrigue a utilizar getters e setters? Eu particularmente desconheço.
Abraços.
Andre_Fonseca
Se vc se enganou ao criar um método com double que deveria ter a exatidão de BigDecimal e ainda vai a tempo de alterar faça um simples refractoring da classe. Se a classe já está em produção marque o método como deprecated, explique que ele não têm a exatidão necessária e que o método getSomeBigger deve ser usado em vez. Explique que o método getSome será retirado da API na versão x.y.z. O método getSomeBigger é um método novo. O método getSome permanece inalterado.
Me corrigam se eu estiver errado, mas para resolver isso você poderia usar um pattern do GOF chamado Adapter que tem outro exemplo de implementação em java aqui
sergiotaborda
Se esse era o seu ponto, o seu exemplo não o demonstra. Não ha nenhuma intenção secundária nas minhas palavras. Quando a forma interna dos objetos muda o seu exterior não muda e vice versa. Isso é encapsulamento. O seu exemplo parecia apresentar que quando o interior muda o exterior tb muda. E isso é anti-encapsulamento: a ideia que se o interior muda o exterior tb muda. É isso que o artigo chama a atenção que é um erro.
Quanto ao recurso do deprecated, sim, é uma boa solução para a questão. Mas a solução final para este tipo de problema - se exatidão numérica for importante para o modelo - é um pattern como o Money do PoEAA.
Money é um objeto imutável. Se o seu ponto é que a imutabilidade não resolve o problema, mas a sua solução é usar um padrão de objeto imutável … alguma coisa não faz sentido. Afinal imutabilidade é ajuda ou não a tornar o estado do mais encapsulado ?
(nota :Quando me referi a exatidão me referia a double versus BigDecimal, e não em relação a dinheiro. O seu exemplo não falada nada sobre dinheiro)
Rodrigo_Manhaes
Eu citei o Money como um exemplo de se encapsular um valor numérico e não ter problemas com alterações na representação interna, para as quais o recurso de deprecated é um paliativo. Porém, relendo o thread, meu primeiro post foi bastante truncado mesmo.
Rodrigo_Manhaes
Meu ponto é que não basta. Dai o “nem sempre” no meu primeiro post. Não é qualquer imutabilidade que resolve o problema, mas sim algo mais “sistemático” como o Money.
[edit: o Money, no caso, é tão-somente um exemplo, não tem mesmo nada a ver com dinheiro]
peerless
Se vc se enganou ao criar um método com double que deveria ter a exatidão de BigDecimal e ainda vai a tempo de alterar faça um simples refractoring da classe. Se a classe já está em produção marque o método como deprecated, explique que ele não têm a exatidão necessária e que o método getSomeBigger deve ser usado em vez. Explique que o método getSome será retirado da API na versão x.y.z. O método getSomeBigger é um método novo. O método getSome permanece inalterado.
Me corrigam se eu estiver errado, mas para resolver isso você poderia usar um pattern do GOF chamado Adapter que tem outro exemplo de implementação em java aqui
vc está errado.
sergiotaborda
André Fonseca:
sergiotaborda:
Se vc se enganou ao criar um método com double que deveria ter a exatidão de BigDecimal e ainda vai a tempo de alterar faça um simples refractoring da classe. Se a classe já está em produção marque o método como deprecated, explique que ele não têm a exatidão necessária e que o método getSomeBigger deve ser usado em vez. Explique que o método getSome será retirado da API na versão x.y.z. O método getSomeBigger é um método novo. O método getSome permanece inalterado.
Me corrigam se eu estiver errado, mas para resolver isso você poderia usar um pattern do GOF chamado Adapter
Sim e não. Na verdade não.
O Adapter, como o nome indica, serve para adaptar. Serve para transformar a interface de objeto em outra.
No caso isso é o que não queremos fazer. Queremos mudar o interior da classe sem mudar o seu exterior ( a sua interface).
O Adapter não nos ajuda já que não teria acesso ao interior da classe.
No caso inverso de ter que criar um método que retorne BigDecimal, sem alterar mais nada, ai poderíamos considerar um Adapter.
Contudo, essa técnica só é usada se não tivermos controle sobre a classe que queremos mudar. Caso em que, simplesmente alteramos a interface , documentamos, e pronto.
Ou seja, neste caso, Adapter não seria a solução.
peerless
resumindo, o adapter desvirtua um cidadão, para libertar outros… hehehehe
Andre_Fonseca
Entendi, valeu pela explicação Sérgio… isso é para eu aprender a ler melhor o problema antes de achar uma possível solução… rs
sergiotaborda
Eu estava procurando por outra coisa quando me deparei com os Java Coding Conventions (1989). Já nessa época era claro o problema do get/set
A chamada para o structs vc class é interessante. Em java temos que usar classes como se fossem estruturas e é ai que mora o perigo ( quando usamos classes que são clases, mas lhe damos poderes de estruturas)
Andre_Fonseca
Pessoal,
Surgiu uma dúvida agora, aqui no projeto nós temos algumas classes de negócio que realizam processos que muitas vezes possuem coisas em comum..
Essas classes possuem o que poderia ser considerado um struct conforme o pessoal falou acima, mas esse struct pode possuir alguns atributos que são diferentes em algumas das classes de negócio.
A minha dúvida é, para essas classes como passar os parâmetros para os processos de negócio??
Utilizando um construtor com os atributos? Utilizando sets e gets na própria classe? E como facilitar para o caso de algumas classes de negócio possuírem atributos em comum??
ClasseNegocio cn1 = new ClasseNegocio()
cn1.setAttrr1('foo');
cn1.setAttrr2('bar');
cn1.executaProcesso();
Neste caso eu acho que a forma mais fácil seria assim:
ObjetoVOClasse1 obj1 = new ObjetoVOClasse1();
obj1.setAttr1('foo');
obj1.setAttr2('bar);
ClasseNegocio cn1 = new ClasseNegocio(obj1);
cn1.executaProcesso();
Porque eu acho que a alternativa 3 é a mais facil para o meu problema??
1) Este objeto contendo os atributos pode ser usados em mais de uma classe de negócio em um ou mais sub-processos dessas classes
2) Fica mais fácil você olhando para o objeto saber o tipo dos atributos e também a ordem em que eles são passados, caso fossemos passar por contrutores tem alguns que teriam que ter até uns 13, 15 atributos
3) É bem provável que esses atributos mudem durante o desenvolvimento, e mesmo depois do sistema em produção
Bom, eu tb não sei direito como resolver, se tiverem sugestões desde já agradeço..
O que eu estou pensando nem é em usar o padrão xpto que é logico melhoraria, estou pensando mesmo em facilidade de manutenção e reuso..
[]´s
sergiotaborda
André Fonseca:
Pessoal,
Surgiu uma dúvida agora, aqui no projeto nós temos algumas classes de negócio que realizam processos que muitas vezes possuem coisas em comum…
Essas classes possuem o que poderia ser considerado um struct conforme o pessoal falou acima, mas esse struct pode possuir alguns atributos que são diferentes em algumas das classes de negócio.
A minha dúvida é, para essas classes como passar os parâmetros para os processos de negócio??
Utilizando um construtor com os atributos? Utilizando sets e gets na própria classe? E como facilitar para o caso de algumas classes de negócio possuírem atributos em comum??
A primeira coisa é : sem saber que atributos são não ha como ajudar , i.e. conhecer o dominio é essencial a fazer uma boa modelagem. Não existem receitas , existem conceitos.
Segundo, se existem muitos atributos (15 !?!?) alguma coisa está errada. Tlv esses atributos têm que ser agrupados eles mesmos.
(sem saber o que são, não tem como falar)
A opção viável é criar um Builder. Ou seja, uma classe que constrói outra. Vc vai lançandos os valores e o builder vai armazenando
no fim ele cria o objeto de comando para ser executado depois.
Outra opção é não usar o construtor mas um método de construção. Isso é mais flexivel já que internamente o acesso perviligiado do método tornas a coisas mais simples
Analisar a granularidade : pode agrupar os atributos ? faz sentido ?
Usar builder
Usar método de construção em vez de construtor.
Attributos iguais não significam nada ( aka não use herança para os agrupar). Mas podem ser candidados a constituir um novo objeto que os agregue.
Andre_Fonseca
Porque vc precisa saber quais atributos são?? Disse que são muitos, podem mudar a qualquer momento e grande parte deles pode ser reutilizada em outros processos de negócio… por isso a minha idéia de agrupar eles em um struct ou VO para facilitar a manutenção …
Sim, alguma coisa está errada, estamos lidando com vários sistemas legados que não possuem bases normalizadas e construídas para serem utilizadas por uma arquitetura OO de forma eficiente … de novo, o que o fato de saber quais atributos são pode ajudar aqui??
Vou dar uma pesquisada nesse caso…
Não vi o que isso poderia ajudar, já que o problema principal: facilitar a manutenção de um struct de dados continua, já que o método fromABC(a,b,c) poderia ter que ser alterado por from(x,p,a,b,c)… posso não ter entendido direito, você poderia colocar mais um exemplo por favor??
sergiotaborda:
Attributos iguais não significam nada ( aka não use herança para os agrupar). Mas podem ser candidados a constituir um novo objeto que os agregue.
O que isso tem de diferente em criar um VO?? ou seja, uma classe com atributos privatos e métodos get e set publicos?? A minha dúvida aqui é quando é uma boa prática criar um VO, apenas quando eu vou trafegar objetos entre camadas de sistemas distribuídos?? ou existem outras situações? eu acho que neste caso que eu coloquei poderia ser uma situação… outra coisa, não são atributos iguais, é um conjunto de atributos que pode ser utilizado em mais de um processo de negócio com alguns atributos diferentes…
D
DaviPiala
A idéia não é facilitar a “manutenção” no objeto de dados e sim evitar que o controle sobre seu estado esteja totalmente em outro objeto que o manipule.
sergiotaborda
Eu falei pq: “conhecer o dominio é essencial para fazer um boa modelagem”
sim, mas para efeitos de modelagem isso significa: “são muitos, não sei quais são, está uma zona” :lol:
Se vc pode criar objetos que agrupem esses outros isso corresponde com a solução que lhe passei.
Porque se “se alguns podem ser usados em outros processos de negocio” significa que alguns não podem. Separar quais podem e quais não podem implica em criar não 1 mas vários objetos para agrupar os atributos. Possivelmente até alguns com atributos repetidos. Apenas conhecendo o dominio é possivel saber quem vai com quem já que essa agrupamento depende do processo de negocio que o utiliza e portanto depende do negocio, do dominio.
como já foi disto esconder o construtor é uma forma de inverter o controle. É o objeto que sabe como se criar e não quem o usa.
Vc pode criar vários métodos de construção sem criar vários construtores ( isso é bom); por exemplo, um que aceite os atrbutos “a vulso” e outro que aceite os VO que quer criar.
Ou seja, criar os objetos de agrupamento é um passo, mas não é o único que vc pode tomar. Como falei antes primeiro tem que analisar a granularidade. Isso significa criar objetos para agrupar os atributos (objetos, plural). quantos e quais depende do dominio. Depende de onde e como vão ser usados. não precisam ser um monte de atributos privados com get/set. Se quer um struct crie um struct, ou seja, use atributos publico mesmo. A menos que exista uma boa razão para os encapsular ( a qual advem do dominio)
É diferente na quantidade. Eu estou dizendo que precisa criar vários e não um só. E estou dizendo tb que não use herança entre eles.
Sempre que tiver problemas de granularidade.Sempre que seus métodos ou contrutores recebam mais de 4 parametros pode começar a desconfiar. Faça uma re-analise.
Isto é exatamente o que vc está fazendo. A sua ideia de usar um objeto para agrupar os atributos é certa.
Apenas lhe passei outras opções, porque, como eu disse, sem conhecer o domínio não tem muito o que dizer.
O fato dos atributos mudarem indica instabilidade do seu modelo. Talvez precisa de algo mais dinâmico. Uma estrutura semelhante a um Map tlv seja o que precisa.
–
Nota: Vc está utilizando VO como sinónimo de “objeto que agrupa outros objetos”. VO é correntemente uma sigla inexata.
“Objecto que agrupa outros objetos” é um TO. VO é um objeto que encapsula valores (value object)
Andre_Brito
Não li o tópico todo, mas li os primeiros posts.
Eu estava com essa mesma dúvida… bati uma semana na mesma moeda, até que criei vergonha na cara e humildade e fui perguntar para o Emerson Macedo. Tirei a liberdade de colocar aqui o que ele me explicou (que por sinal, foi excelente).
Andre_Fonseca
Bom, respondendo ao Sérgio entendi o que você quis dizer, e obrigado pelas sugestões…
Respondendo ao meu xará, acho que o meu problema é um pouco diferente do seu, porque no meu caso eu tenho alguns processos com vários sub-processos de negócio, e neste caso eu tenho um conjunto de atributos comuns que são utilizados por alguns processos e sub-processos, ou seja, não é bem uma entidade do domínio que possui atributos apenas…