Getters e setters são frequentemente criticados por não serem apropriados OO. Por outro lado, a maioria dos códigos OO que eu tenho possui extensores e setters.
Quando justificadores e setters são justificados? Você tenta evitar usá-los? Eles são usados em geral?
Se seu idioma favorito possui propriedades (a minha possui), essas coisas também são consideradas getters e setters para esta pergunta. Eles são a mesma coisa do ponto de vista da metodologia OO. Eles apenas têm uma sintaxe melhor.
Fontes para a crítica Getter / Setter (algumas tiradas dos comentários para oferecer melhor visibilidade):
- http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
- http://typicalprogrammer.com/?p=23
- http://c2.com/cgi/wiki?AccessorsAreEvil
- http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
- http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
- http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Para declarar a crítica simplesmente: Getters e Setters permitem que você manipule o estado interno dos objetos de fora do objeto. Isso viola o encapsulamento. Somente o próprio objeto deve se preocupar com seu estado interno.
E um exemplo de versão procedural do código.
struct Fridge
{
int cheese;
}
void go_shopping(Fridge fridge)
{
fridge.cheese += 5;
}
Versão do código do Mutator:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
Os getters e setters tornaram o código muito mais complicado sem permitir o encapsulamento adequado. Como o estado interno é acessível a outros objetos, não ganhamos muito adicionando esses getters e setters.
A questão foi discutida anteriormente no Stack Overflow:
fonte
Getters and setters are often criticized as being not proper OO
- Citação, por favor.Respostas:
Ter getters e setters, por si só, não quebra o encapsulamento. O que quebra o encapsulamento é adicionar automaticamente um getter e um setter para cada membro de dados (todos os campos , em linguagem java), sem pensar em nada. Embora isso seja melhor do que tornar todos os membros de dados públicos, está apenas a um pequeno passo.
O objetivo do encapsulamento não é que você não consiga saber ou alterar o estado do objeto de fora do objeto, mas deve ter uma política razoável para fazê-lo.
Alguns membros de dados podem ser totalmente internos ao objeto e não devem ter getters nem setters.
Alguns membros de dados devem ser somente leitura, para que possam precisar de getters, mas não de setters.
Alguns membros de dados podem precisar ser mantidos consistentes entre si. Nesse caso, você não forneceria um setter para cada um, mas um método único para defini-los ao mesmo tempo, para que você possa verificar os valores quanto à consistência.
Alguns membros de dados podem precisar ser alterados apenas de uma certa maneira, como incrementados ou decrementados por um valor fixo. Nesse caso, você forneceria um método
increment()
e / oudecrement()
método, em vez de um levantador.No entanto, outros talvez precisem ser de leitura e gravação e teriam um getter e um setter.
Considere um exemplo de a
class Person
. Digamos que uma pessoa tenha um nome, um número de previdência social e uma idade. Digamos que não permitimos que as pessoas mudem seus nomes ou números de previdência social. No entanto, a idade da pessoa deve ser aumentada em 1 a cada ano. Nesse caso, você forneceria um construtor que inicializaria o nome e o SSN com os valores fornecidos e inicializaria a idade para 0. Você também forneceria um métodoincrementAge()
, que aumentaria a idade em 1. Você também forneceria getters para todos os três. Nenhum setter é necessário neste caso.Nesse design, você permite que o estado do objeto seja inspecionado de fora da classe e que ele seja alterado de fora da classe. No entanto, você não permite que o estado seja alterado arbitrariamente. Existe uma política que afirma efetivamente que o nome e o SSN não podem ser alterados e que a idade pode ser aumentada em 1 ano por vez.
Agora, digamos que uma pessoa também tenha um salário. E as pessoas podem mudar de emprego à vontade, o que significa que seu salário também mudará. Para modelar essa situação, não temos outra maneira senão fornecer um
setSalary()
método! Permitir que o salário seja alterado à vontade é uma política perfeitamente razoável nesse caso.A propósito, no seu exemplo, eu daria à classe
Fridge
os métodosputCheese()
etakeCheese()
, em vez deget_cheese()
eset_cheese()
. Então você ainda teria encapsulamento.fonte
A razão básica para getters e setters em Java é muito simples:
Portanto, se você deseja permitir a passagem de um campo pela interface, precisará de um método de leitura e gravação. Estes são tradicionalmente chamados de getX e setX para o campo x.
fonte
Em http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
Estilo JavaBean:
Estilo OO:
Bem, claramente prefiro a última abordagem; ele não sangra os detalhes da implementação, é mais simples e conciso, e todas as informações necessárias são incluídas na chamada do método, por isso é mais fácil acertar. Também prefiro definir membros privados usando parâmetros no construtor, sempre que possível.
Sua pergunta é: quando um getter / setter se justifica? Talvez quando seja necessária uma mudança de modo ou você precise interrogar um objeto para obter algumas informações.
Ao pensar nisso, quando comecei a codificar em C #, escrevi muito código no estilo Javabeans ilustrado acima. Mas, à medida que ganhei experiência no idioma, comecei a definir mais os membros no construtor e a usar métodos que se pareciam mais com o estilo OO acima.
fonte
Quando o comportamento "get" e "set" correspondem realmente ao comportamento do seu modelo, o que é praticamente nunca .
Qualquer outro uso é apenas uma trapaça, porque o comportamento do domínio comercial não é claro.
Editar
Essa resposta pode parecer irreverente, então deixe-me expandir. As respostas acima são na maioria corretas, mas focam nos paradigmas de programação do design de OO e alguns que perdem o quadro geral. Na minha experiência, isso leva as pessoas a pensar que evitar gettings e setters é uma regra acadêmica para linguagens de programação OO (por exemplo, as pessoas pensam que substituir getters por propriedades é grande)
De fato, é uma conseqüência do processo de design. Você não precisa entrar em interfaces, encapsulamentos e padrões, discutindo se isso quebra ou não esses paradigmas e o que é ou não uma boa programação OO. O único ponto que importa em última análise é que, se não houver nada no seu domínio que funcione assim, colocando-o em você, você não está modelando seu domínio.
A realidade é que é altamente improvável que qualquer sistema em seu espaço de domínio tenha getters e setters. Você não pode ir até o homem ou a mulher responsável pela folha de pagamento e simplesmente dizer "Defina este salário como X" ou "Consiga esse salário para mim" . Esse comportamento simplesmente não existe
Se você está colocando isso em seu código, não está projetando seu sistema para corresponder ao modelo do seu domínio. Sim, isso quebra as interfaces e o encapsulamento, mas esse não é o ponto. O ponto é que você está modelando algo que não existe.
Além disso, você provavelmente está perdendo uma etapa ou processo importante, porque provavelmente existe uma razão pela qual eu não posso simplesmente andar para pagar a folha e dizer definir esse salário para X.
Quando as pessoas usam getters e setters, elas tendem a empurrar as regras desse processo para o lugar errado. Isso está se afastando ainda mais do seu domínio. Usando o exemplo do mundo real, é como salário assumindo que a pessoa aleatória que entrou tem permissão para obter esses valores, caso contrário ele não estaria pedindo por eles. Não só não é assim que o domínio é, como também está mentindo sobre como é o domínio.
fonte
set/get
salário?Como regra geral, getters e setters são uma má idéia. Se um campo não faz parte da interface e você o torna privado, tudo bem. Se fizer parte da interface e você a tornar pública, tudo bem. Mas se você torná-lo privado e depois se virar e torná-lo efetivamente público novamente, fornecendo um getter e um setter, você volta ao ponto em que começou, exceto que seu código está agora mais detalhado e ofuscado.
Obviamente, há exceções. Em Java, pode ser necessário usar interfaces. A biblioteca padrão Java possui requisitos de compatibilidade com versões anteriores tão extremas que superam as medidas normais de qualidade de código. É até possível que você esteja lidando com o caso lendário, mas raro, em que há uma boa chance de substituir um campo armazenado posteriormente pelo cálculo em tempo real sem interromper a interface. Mas essas são exceções. Getters e setters são um anti-padrão que precisa de justificativa especial.
fonte
se o campo é acessível diretamente ou via método não é realmente importante.
Invariantes de classe (úteis) são importantes. E para preservá-los, às vezes precisamos não conseguir mudar algo de fora. Por exemplo. se tivermos a classe Square com largura e altura separadas, alterar uma delas fará com que ela se torne algo além de square. Então, precisamos do método changeSide Se fosse Retângulo, poderíamos ter setters / public field. Mas o setter do que testaria se seu maior que zero seria melhor.
E em linguagens concretas (por exemplo, java), existem razões pelas quais precisamos desses métodos (interfaces). E outro motivo para o método é a compatibilidade (fonte e binário). Portanto, é mais fácil adicioná-los e depois pensar se o campo público seria suficiente.
btw. Eu gosto de usar um valor imutável simples, segurando classes com campos finais públicos.
fonte
Você pode alterar seus internos para o que for, mantendo as interfaces iguais. Se suas interfaces não variarem, elas codificadas não serão quebradas. Você ainda pode alterar seus internos conforme desejar.
fonte
Minha abordagem é essa -
Quando espero me interessar pelos dados mais tarde, um getter / setter é justificado. Além disso, se a mudança está acontecendo, muitas vezes eu empurro os dados para um getter / setter.
Se for uma estrutura POD, deixo os slots disponíveis.
Em um nível mais abstrato, a questão é "quem gerencia os dados", e isso depende do projeto.
fonte
Se o uso de getters e setters parecer complicado, o problema pode ser a linguagem, não o próprio conceito.
Aqui está o código do segundo exemplo escrito em Ruby:
Observe que se parece muito com o primeiro exemplo em Java? Quando getters e setters são tratados como cidadãos de primeira classe, eles não são uma tarefa fácil de usar, e a flexibilidade adicionada às vezes pode ser um benefício real - por exemplo, poderíamos decidir retornar um valor padrão para queijo em uma geladeira nova:
É claro que haverá muitas variáveis que não devem ser expostas publicamente. A exposição desnecessária de variáveis internas tornará seu código pior, mas você dificilmente pode culpar os getters e setters.
fonte
Considere uma
Size
classe que encapsula largura e altura. Posso eliminar setters usando o construtor, mas como isso me ajuda a desenhar um retânguloSize
? Largura e altura não são dados internos da classe; são dados compartilhados que devem estar disponíveis para os consumidores do Size.Objetos consistem em comportamentos e estados - ou atributos. Se não houver estado exposto, apenas os comportamentos serão públicos.
Sem estado, como você classificaria uma coleção de objetos? Como você procuraria por uma instância específica de um objeto? Se você usa apenas construtores, o que acontece quando seu objeto tem uma longa lista de atributos?
Nenhum parâmetro de método deve ser consumido sem validação. Portanto, é preguiça de escrever:
Se você escrever dessa maneira, pelo menos se preparou para usar o setter para validação; é melhor do que um campo público - mas apenas por pouco. Mas, pelo menos, você tem uma interface pública consistente que pode retornar e aplicar regras de validação sem quebrar o código de seus clientes.
Getters, setters, propriedades, mutadores, chame-os como quiser, mas eles são necessários.
fonte
int
variável de instância, por exemplo, e imagine que você decide adicionar uma regra de validação para aceitar apenas valores não negativos. O problema é que o código do seu cliente já pode contar com a possibilidade de configurá-lo para um valor negativo ...Se getters e setters violam o encapsulamento e o verdadeiro OO, então estou seriamente com problemas.
Eu sempre senti que um objeto representa o que melhor vem à mente que você precisa.
Acabei de escrever um programa que gera Mazes em Java e tenho uma classe que representa "Maze Squares". Eu tenho dados nesta classe que representam coordenadas, paredes e booleanos etc.
Eu tenho que ter alguma maneira de alterar / manipular / acessar esses dados! O que faço sem getters e setters? Java não usa propriedades e definir todos os meus dados locais para essa classe como público é DEFINITIVAMENTE uma violação do encapsulamento e do OO.
fonte
Em primeiro lugar, existem amplamente dois tipos de objetos que comentarei, tipos de valor e serviço.
Os tipos de serviço nunca devem ter setters, quaisquer que sejam as dependências necessárias, não devem ser obtidas. A melhor maneira de passar dependências é através de um construtor ou fábrica, assim todas as instâncias são totalmente formadas desde o início, pura e simplesmente.
Os tipos de valor também devem ser imutáveis, por outro lado, há momentos em que isso não é prático, como um ORM, ou algum outro mapeamento, como de um widget para um objeto. Todos os outros tipos de valores que passam pelo sistema de uma camada ou parte para outra devem ser imutáveis e não devem ter setters.
fonte
Um Getter / Setter é justificado como qualquer outro método público. A justificativa é principalmente porque queremos fornecer uma interface para o mundo externo que defina como nossa classe interage com outras classes. Fazemos isso principalmente porque queremos reduzir o acoplamento entre entidades separadas. Reduzir o acoplamento é uma coisa boa por vários motivos:
fonte
Sim, getters e setters é um antipadrão na programação orientada a objetos e nunca deve ser usado: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . Em poucas palavras, eles não se encaixam no paradigma orientado a objetos porque incentivam você a tratar um objeto como uma estrutura de dados. Qual é um grande equívoco.
fonte
Espero que tudo o que o IDE desenvolvido pela empresa que desenvolve sua linguagem de programação gera automaticamente não viole os "Princípios de Orientação a Objetos".
Dito isto, toda vez que você tiver uma variável de escopo público, use um getter e um setter e ficará com o ouro. Parece-me o elemento necessário do princípio do encapsulamento extremamente orientado a objetos - mesmo que pareça um monte de código indesejável.
A razão para usá-los é que o encapsulamento adequado ainda pode ocorrer e, desde que você abstraia a camada que permite que a pessoa que mexe com seu objeto sinta seu objeto, você pode levá-lo embora sem que ele saiba direito?
Basta dizer que uma casa dividida não suporta, um dos inquilinos da OO não se liga e você não pode servir ao encapsulamento e à otimização prematura.
fonte
Eu pensei que teríamos respostas mais comuns aqui?
Os getters e setters geralmente são extremamente OOP (qualquer pessoa que esteja dizendo algo errado, é simples assim).
Embora você precise se lembrar de não ter engenheiro em excesso, nunca faça um getter ou setter que não seja necessário. Qualquer informação que você não utilize por outra classe, não deve ter nenhum getter ou setter.
Porém, a razão pela qual você não torna os campos públicos e, em vez disso, tem getters e setters é principalmente:
Não é possível fazer testes adequados usando campos. Getters / setters são muito melhores nesse sentido.
É impossível usar corretamente os campos em uma configuração de programação em tempo real. Getters / setters sincronizados é o caminho a percorrer.
O tópico da interface (já explicado, então não vou).
É mais fácil de usar ao reutilizar o sistema corretamente.
É muito mais difícil saber quais classes estão usando sua classe e o que será interrompido se você alterar um campo do que um getter / setter.
Portanto, a única vez em que você usa um campo público em vez de um getter / setter é quando você não faz um projeto oficial, mas apenas por diversão e não pode se incomodar com o getter / setter.
fonte