Qual é um problema preciso em permitir getters?

15

Não estou procurando uma opinião sobre semântica, mas simplesmente para um caso em que ter getters usados ​​com sensatez é um impedimento real. Talvez isso me jogue em uma espiral interminável de confiar neles, talvez a alternativa seja mais limpa e lide com getters automaticamente, etc. Algo concreto.

Ouvi todos os argumentos, ouvi dizer que eles são ruins porque forçam você a tratar objetos como fontes de dados, que violam o "estado puro" de "um objeto" não revelam muito, mas estejam preparados para aceite muito ".

Mas absolutamente nenhuma razão sensata para o fato de que uma getDatacoisa é ruim, de fato, algumas pessoas argumentaram que se trata muito de semântica, getters tão bons por si só, mas simplesmente não os nomeie getXpara mim, isso é pelo menos engraçado .

O que é uma coisa, sem opiniões, que será interrompida se eu usar getters de maneira sensata e para dados que claramente a integridade do objeto não se quebra se for divulgada?

É claro que permitir um getter para uma string usada para criptografar algo está além do absurdo, mas estou falando de dados que seu sistema precisa para funcionar. Talvez seus dados sejam extraídos de um Providerobjeto, mas, ainda assim, o objeto ainda precisa permitir Providerque você faça um $provider[$object]->getData, não há como contorná-lo.


Por que estou perguntando: para mim, os getters, quando usados ​​com sensibilidade e em dados que são tratados como "seguros" são enviados por Deus, 99% dos meus getters são usados ​​para identificar o objeto, como, pergunto, por meio de código Object, what is your name? Object, what is your identifier?, quem trabalha com um objeto deve saber essas coisas sobre um objeto, porque quase tudo sobre programação é identidade e quem mais sabe melhor o que é que o próprio objeto? Portanto, não vejo problemas reais, a menos que você seja um purista.

Examinei todas as perguntas do StackOverflow sobre "por que os getters / setters" são ruins e, embora eu concorde que os setters são realmente ruins em 99% dos casos, os getters não precisam ser tratados da mesma forma apenas porque rimam.

Um setter compromete a identidade do seu objeto e dificulta a depuração de quem está alterando os dados, mas um getter não está fazendo nada.

coolpasta
fonte
2
Meu conselho é esquecer a maior parte da teoria OO. Prática. Escreva muito código e mantenha-o. Você aprenderá muito, muito, muito mais sobre o que funciona bem e o que não funciona, de fato, fazendo algo e voltando a ele alguns meses depois.
Jpmc26
1
@ jpmc26 O que na mãe de .... Eu nunca percebi que nenhum de nós realmente faz OOP corretamente, eu sempre tive essa noção de encapsulamento estritamente relacionada aos campos de um objeto, mas o objeto em si é um estado e está sendo compartilhado livremente. Genuinamente todo mundo está fazendo OOP errado, então, ou melhor, OOP não é possível se o paradigma for objetos. Uso OOP estritamente para expressar como um sistema funciona e nunca o tratou como o santo graal, nem o SOLID. São apenas ferramentas que eu uso principalmente para definir uma razoavelmente bem esperada (através da implementação) do meu conceito. Alguma leitura sobre se está certo?
Coolpasta 6/05/19
2
--cont, Quanto mais eu escrevo, mais percebo que a programação é capaz de abstrair o máximo que é necessário para poder raciocinar com outras pessoas e com você sobre sua base de código. Obviamente, o lado técnico disso é garantir que você faça as verificações adequadas / defina as regras corretas. Na verdade, quem consegue fazer os outros entenderem melhor seu código ganha. Certifique-se de que faça sentido para quem o lê, e não falhe ao segmentar corretamente os objetos com interfaces, verificar e alternar para outros paradigmas quando for mais fácil argumentar com eles: seja flexível.
Coolpasta 6/05/19
2
Isso me parece um palhaço. Não acredito que nenhum desenvolvedor sério que realmente escreva código utilizável argumentaria que o uso de getters com sensibilidade é um problema. A questão implica que os getters podem ser usados ​​com sensibilidade, o que implica que os getters podem ser mais sensíveis. Você está procurando alguém para dizer que não há uso sensato de getters? Você estará esperando por um tempo.
JimmyJames
2
@coolpasta Você está certo. Eu realmente não me importo se é pura OOP. Apenas melhor. Dê-me uma escolha entre código quebrado que pode ser entendido por humanos versus código perfeito para a CPU que é indecifrável e eu sempre levo o código amigável para humanos. OOP só é útil para mim quando reduz o número de coisas em que tenho que pensar a qualquer momento. Essa é a única razão pela qual gosto mais de procedimentos diretos. Sem isso, você está apenas me fazendo pular através de vários arquivos de código-fonte sem motivo.
Candied_orange 8/05/19

Respostas:

22

Você não pode escrever um bom código sem getters.

A razão disso não é porque os getters não quebram o encapsulamento, eles o fazem. Não é porque os getters não tentam as pessoas a não se incomodarem em seguir o POO, o que os levaria a colocar métodos com os dados em que atuam. Eles fazem. Não, você precisa de getters por causa dos limites.

As idéias de encapsulamento e manutenção de métodos juntamente com os dados em que atuam simplesmente não funcionam quando você se depara com um limite que impede você de mover um método e, portanto, obriga a mover dados.

É realmente assim tão simples. Se você usa getters quando não há limites, acaba sem objetos reais. Tudo começa a tender para o procedimento. O que funciona tão bem quanto nunca.

OOP verdadeiro não é algo que você pode espalhar por toda parte. Funciona apenas dentro desses limites.

Esses limites não são muito finos. Eles têm código neles. Esse código não pode ser OOP. Também não pode ser funcional. Nenhum código tem nossos ideais retirados para que ele possa lidar com a dura realidade.

Michael Fetters chamou esse código de fáscia, depois daquele tecido conjuntivo branco que mantém seções de uma laranja juntas.

Esta é uma maneira maravilhosa de pensar sobre isso. Ele explica por que não há problema em ter os dois tipos de código na mesma base de código. Sem essa perspectiva, muitos novos programadores se apegam a seus ideais com força, então partem seus corações e desistem desses ideais quando atingem seu primeiro limite.

Os ideais funcionam apenas em seu devido lugar. Não desista deles só porque eles não funcionam em todos os lugares. Use-os onde eles trabalham. Esse lugar é a parte suculenta que a fáscia protege.

Um exemplo simples de limite é uma coleção. Isso contém algo e não faz ideia do que é. Como um designer de coleção poderia mover a funcionalidade comportamental do objeto em espera para a coleção quando não tem idéia do que ele estará segurando? Você não pode. Você está enfrentando um limite. É por isso que as coleções têm getters.

Agora, se você soubesse, poderia mudar esse comportamento e evitar o estado de mudança. Quando você sabe, você deveria. Você nem sempre sabe.

Algumas pessoas chamam isso de pragmático. E isso é. Mas é bom saber por que temos que ser pragmáticos.


Você expressou que não deseja ouvir argumentos semânticos e parece estar defendendo a colocação de "apanhadores sensatos" em todos os lugares. Você está pedindo que essa ideia seja contestada. Acho que posso mostrar que a ideia tem problemas com a maneira como você a estruturou. Mas também acho que sei de onde você vem, porque eu estive lá.

Se você quiser getters em todos os lugares, veja Python. Não há palavra-chave privada. No entanto, o Python faz POO muito bem. Quão? Eles usam um truque semântico. Eles nomeiam qualquer coisa que seja privada com um sublinhado principal. Você pode ler o conteúdo, desde que seja responsável por isso. "Somos todos adultos aqui", costumam dizer.

Então, qual é a diferença entre isso e apenas colocar getters em tudo em Java ou C #? Desculpe, mas é semântica. A convenção sublinhada de Pythons indica claramente a você que você está bisbilhotando atrás da única porta dos funcionários. Tapa getters em tudo e você perde esse sinal. Com a reflexão, você poderia ter retirado o privado de qualquer maneira e ainda não ter perdido o sinal semântico. Simplesmente não há um argumento estrutural a ser feito aqui.

Então, o que nos resta é o trabalho de decidir onde pendurar a placa "apenas funcionários". O que deve ser considerado privado? Você chama isso de "receptores sensatos". Como eu disse, a melhor justificativa para um getter é um limite que nos afasta de nossos ideais. Isso não deve resultar em getters sobre tudo. Quando isso resulta em um getter, você deve considerar mover o comportamento ainda mais para a parte interessante, onde você pode protegê-lo.

Essa separação deu origem a alguns termos. Um objeto de transferência de dados ou DTO não possui comportamento. Os únicos métodos são getters e às vezes setters, às vezes um construtor. Esse nome é lamentável, porque não é um objeto verdadeiro. Os getters e setters são realmente apenas códigos de depuração que oferecem um local para definir um ponto de interrupção. Se não fosse por essa necessidade, eles seriam apenas uma pilha de campos públicos. Em C ++, costumávamos chamá-los de estruturas. A única diferença que eles tinham de uma classe C ++ era o padrão para o público.

Os DTOs são bons porque você pode jogá-los sobre um muro de fronteira e manter seus outros métodos com segurança em um bom objeto de comportamento interessante. Um verdadeiro objeto. Sem getters para violar, é encapsulamento. Meus objetos de comportamento podem comer DTOs usando-os como Objetos de Parâmetro . Às vezes, tenho que fazer uma cópia defensiva para impedir o estado mutável compartilhado . Eu não espalhe DTOs mutáveis ​​por dentro da parte suculenta dentro dos limites. Eu os encapsulo. Eu os escondo. E quando finalmente encontro um novo limite, lancei um novo DTO e o joguei por cima do muro, tornando-o o problema de outra pessoa.

Mas você deseja fornecer getters que expressam identidade. Bem, parabéns, você encontrou um limite. As entidades têm uma identidade que vai além de sua referência. Ou seja, além do endereço de memória. Portanto, tem que ser armazenado em algum lugar. E algo tem que ser capaz de se referir a isso por sua identidade. Uma pessoa que expressa identidade é perfeitamente razoável. Uma pilha de código que usa esse getter para tomar decisões que a Entidade poderia ter tomado por si mesma não é.

No final, não é a existência de getters que está errada. Eles são muito melhores que os campos públicos. O que é ruim é quando eles são usados ​​para fingir que você está sendo orientado a objetos quando não está. Getters são bons. Ser orientado a objetos é bom. Os getters não são orientados a objetos. Use getters para criar um local seguro para se orientar a objetos.

candied_orange
fonte
Foi exatamente por isso que perguntei e não tenho certeza se minha conversa é visível com Robert. Também estava tentando descobrir um caso específico em que claramente me dói usar "getters sensíveis". Eu, por mim mesma, discordo dos levantadores porque, pelo menos para mim, é muito difícil atribuir propriedade a uma ação como essa, eu costumava usar levantadores em tudo e quando percebi que mesmo um levantador, quando afetado por muitos objetos, mata eu ... tive que reescrever tudo. O uso sensato de getters, após testes exaustivos por tanto tempo, seriamente não tem desvantagens se você não é um purista.
Coolpasta 5/05
1
@coolpasta você pode criar objetos do proprietário dos dados. Os objetos do proprietário dos dados são objetos de dados, mas são projetados e nomeados para que eles (claramente) sejam os proprietários. Claro que esses objetos terão getters.
Rwong 5/05
1
@rwong Como assim clearly? Se dados são passados ​​para mim a partir de algo, claramente , por valor , meu objeto agora é o proprietário dos dados, mas pela semântica, ainda não, nesse ponto, simplesmente obtém os dados de outra pessoa. Em seguida, ele deve executar operações para transformar esses dados, tornando-os próprios, no momento em que os dados são tocados, você deve fazer alterações semânticas: você recebeu dados nomeados como $data_from_requeste agora operou? Dê um nome $changed_data. Deseja expor esses dados a outras pessoas? Crie um getter getChangedRequestData, então, a propriedade está claramente definida. Ou é?
Coolpasta 5/05
1
"Você não pode escrever um bom código sem getters." Isso é totalmente errado, assim como a noção de que limites inerentemente precisam de getters. Isso não é pragmatismo, apenas preguiça. É um pouco mais fácil simplesmente jogar dados por cima do muro e terminar com eles, é difícil pensar em casos de uso e projetar uma boa API comportamental .
Robert Bräutigam
2
Excelente resposta!
cmaster - restabelece monica 5/05/19
10

Os getters violam o Princípio de Hollywood ("Não ligue para nós, ligaremos para você")

O Princípio de Hollywood (aka Inversão de Controle) afirma que você não chama o código da biblioteca para fazer as coisas; em vez disso, a estrutura chama seu código. Como a estrutura controla as coisas, não é necessário transmitir seu estado interno aos clientes. Você não precisa saber.

Na sua forma mais insidiosa, violar o Princípio de Hollywood significa que você está usando um getter para obter informações sobre o estado de uma classe e, em seguida, toma decisões sobre quais métodos chamar nessa classe com base no valor que você obtém. é uma violação do encapsulamento no seu melhor.

Usar um getter implica que você precisa desse valor quando realmente não precisa .

Você pode realmente precisar dessa melhoria de desempenho

Em casos extremos de objetos leves que devem ter o máximo desempenho possível, é possível (embora extremamente improvável) que você não possa pagar a penalidade de desempenho muito pequena que um getter impõe. Isso não acontecerá 99,9% das vezes.

Robert Harvey
fonte
1
Entendo e voarei com sua verdade, que não preciso saber. . Mas cheguei a um ponto em que preciso. Eu tenho um Generatorobjeto que percorre todos os meus Itemsobjetos e depois chama getNamecada um Itempara fazer algo mais. Qual é o problema com isso? Então, em troca, o Generatorcospe strings formatadas. Isso está dentro da minha estrutura, para a qual eu tenho uma API sobre a qual as pessoas podem usar para executar o que os usuários fornecem, mas sem tocar na estrutura.
Coolpasta 5/05/19
3
What is the issue with this?Nada que eu possa ver. Isso é essencialmente o que uma mapfunção faz. Mas essa não é a pergunta que você fez. Você essencialmente perguntou: "Existem quaisquer condições em que um getter pode ser desaconselhável." Eu respondi com dois, mas isso não significa que você abandona completamente os levantadores.
Robert Harvey
1
Você está fazendo essa pergunta ao cara errado. Sou pragmático; Faço o que melhor se adequa aos meus programas específicos e não ponho muito em "princípios" a menos que sirvam aos meus propósitos.
Robert Harvey
2
@ jpmc26: Estruturas. Não bibliotecas.
Robert Harvey
2
Uma estrutura é uma tentativa de transformar uma linguagem de propósito geral em uma linguagem específica de domínio. Uma biblioteca é uma coleção de algoritmos reutilizáveis. Qualquer um pedirá que você dependa disso. Depende de você se você quiser codificar a dependência ou tornar a dependência facilmente substituível.
Candied_orange
2

Getters vazam detalhes de implementação e abstração de interrupção

Considerar public int millisecondsSince1970()

Seus clientes pensam "oh, isso é um int" e haverá um zilhão de chamadas supondo que seja um int , fazendo matemática inteira comparando datas, etc ... Quando você perceber que precisa de muito tempo , haverá muitas do código legado com problemas. Em um mundo Java, você adicionaria @deprecatedà API, todo mundo a ignorará e você ficará impedido de manter um código obsoleto e com erros. :-( (Presumo que outras línguas sejam semelhantes!)

Nesse caso em particular, não tenho certeza de qual seria a melhor opção, e a resposta @candiedorange está totalmente correta, há muitas ocasiões em que você precisa de getters, mas este exemplo ilustra as desvantagens. Todo public getter tende a "trancar" você em uma determinada implementação. Use-os se você realmente precisar "ultrapassar fronteiras", mas use o mínimo possível e com cuidado e prudência.

user949300
fonte
Isso é verdade, mas qual é a solução padrão para impor um tipo / estrutura de dados à variável de um objeto, bem como a qualquer coisa que use o getter para essa variável?
Coolpasta 5/05
1
Este exemplo ilustra um fenômeno diferente, a obsessão primitiva. Atualmente, a maioria das bibliotecas e estruturas possui classes que representam timepointe timespanrespectivamente. ( epoché um valor particular de timepoint.) Nessas classes, eles fornecem getters como getIntou getLongou getDouble. Se as classes que manipulam o tempo são escritas para que (1) delegem aritmética relacionada ao tempo a esses objetos e métodos, e (2) forneçam acesso a esses objetos de tempo por meio de getters, o problema é resolvido, sem a necessidade de se livrar dos getters .
rwong 5/05/19
1
Para resumir, os getters fazem parte da API e, portanto, precisam ser projetados com considerações suficientes para todas as consequências, incluindo as passadas, atuais e futuras. Mas isso não leva à conclusão de evitar ou minimizar o número de getters. De fato, se houver uma necessidade futura de acessar uma determinada informação para a qual um getter foi omitido, isso exigiria uma alteração na API e no código da biblioteca. Assim, a decisão sobre se um getter específico deve ser implementado ou evitado deve se basear no domínio e na intenção, não por razões preventivas.
rwong 5/05/19
1
"millisecondsSince1970" parou de funcionar por 32 ints bit antes do final de Janeiro de 1970, assim que eu duvido que haja muito código usá-lo :-)
gnasher729
1
@rwong Um pouco correto, mas você supõe que as bibliotecas preferidas que representam os pontos temporais são estáveis. O que eles não são. Por exemplo moment.js
user949300
1

Eu acho que a primeira chave é lembrar que os absolutos estão sempre errados.

Considere um programa de catálogo de endereços, que simplesmente armazena as informações de contato das pessoas. Mas, vamos fazer o certo e dividir em camadas de controlador / serviço / repositório.

Não vai ser uma Personclasse que contém dados reais: nome, endereço, número de telefone, etc .. Addresse Phonesão classes, também, para que possamos utilizar polimorfismo, mais tarde, aos regimes de apoio não-americanos. Todas as três classes são objetos de transferência de dados , portanto, não serão mais que getters e setters. E isso faz sentido: eles não terão nenhuma lógica além da substituição equalse getHashcode; pedir para que você forneça uma representação das informações de uma pessoa completa não faz sentido: é para apresentação em HTML, um aplicativo GUI personalizado, um aplicativo de console, um ponto de extremidade HTTP etc.?

É aí que entram o controlador, o serviço e o repositório. Todas essas classes serão muito lógicas e leves, graças à injeção de dependência.

O controlador receberá um serviço injetado, o que expõe métodos como gete save, os quais terão alguns argumentos razoáveis ​​(por exemplo, getpodem ter substituições para pesquisar por nome, pesquisar por CEP ou apenas obter tudo; saveprovavelmente serão necessários um único Persone salve-o). Quais getters o controlador teria? Ser capaz de obter o nome da classe concreta pode ser útil para o registro, mas que estado ela conterá além do estado que foi injetado nela?

Da mesma forma, a camada de serviço injetará um repositório, para que ele possa realmente obter e persistir Persons, e possa ter alguma "lógica de negócios" (por exemplo, talvez exijamos que todos os Personobjetos tenham pelo menos um endereço ou telefone número). Mas, novamente: que estado esse objeto tem além do que é injetado? Novamente, nenhum.

A camada de repositório é onde as coisas ficam um pouco mais interessantes: ele estabelecerá uma conexão com um local de armazenamento, por exemplo. um arquivo, um banco de dados SQL ou um armazenamento na memória. Aqui é tentador adicionar um getter para obter o nome do arquivo ou a cadeia de conexão SQL, mas esse é o estado que foi injetado na classe. O repositório deve ter um getter para saber se está ou não conectado com êxito ao seu armazenamento de dados? Bem, talvez, mas para que servem essas informações fora da própria classe do repositório? A própria classe do repositório deve ser capaz de tentar se reconectar ao seu armazenamento de dados, se necessário, o que sugere que a isConnectedpropriedade já possui um valor duvidoso. Além disso, uma isConnectedpropriedade provavelmente estará errada exatamente quando mais precisaria estar correta: verificarisConnectedantes de tentar obter / armazenar dados, não garante que o repositório ainda esteja conectado quando a chamada "real" for feita, portanto, não elimina a necessidade de tratamento de exceção em algum lugar (há argumentos para onde isso deve ir além o escopo desta questão).

Considere também testes de unidade (você está escrevendo testes de unidade, certo?): O serviço não espera que uma classe específica seja injetada, mas espera que uma implementação concreta de uma interface seja injetada. Isso permite que o aplicativo como um todo mude onde os dados são armazenados sem ter que fazer nada além de trocar o repositório que está sendo injetado no serviço. Ele também permite que o serviço seja testado por unidade, injetando um repositório simulado. Isso significa pensar em termos de interfaces, em vez de classes. A interface do repositório exporia getters? Ou seja, existe algum estado interno que seria: comum a todos os repositórios, útil fora do repositório e não injetado no repositório? Eu seria pressionado a pensar em qualquer um.

TL; DR

Conclusão: além das classes cujo único objetivo é transportar dados, nada mais na pilha tem um lugar para colocar um getter: o estado é injetado ou irrelevante fora da classe trabalhadora.

minnmass
fonte
Acho essa linha de pensamento muito semelhante ao debate sobre o uso adequado das propriedades de C #. Em suma, espera-se que as propriedades (que podem ser apenas de getter ou de getter-setter-set) mantenham um determinado contrato, como "o que você define é o que obtém", "getter deve estar praticamente livre de efeitos colaterais", "getter deve evitar erros de lançamento", etc. Ao contrário da sua conclusão, existem muitos estados de objetos que são benéficos para serem expostos como propriedades (ou getters). Os exemplos são numerosos demais para citar aqui.
rwong 5/05/19
2
@rwong Gostaria de saber alguns exemplos, digamos, para um aplicativo "normal" "corporativo" implementado por uma equipe. Vamos também assumir, por uma questão de simplicidade, que não há terceiros envolvidos. Você sabe, um sistema independente, como um calendário, pet shop, o que você quiser.
Robert Bräutigam
1

O que é uma coisa, sem opiniões, que será interrompida se eu usar getters de maneira sensata e para dados que claramente a integridade do objeto não se quebra se for divulgada?

Membros mutáveis.

Se você tem uma coleção de coisas em um objeto que você expõe por meio de um getter, você está potencialmente se expondo a erros associados às coisas erradas sendo adicionadas à coleção.

Se você tem um objeto mutável que está expondo por meio de um getter, está potencialmente se abrindo para que o estado interno do seu objeto seja alterado de uma maneira que você não espera.

Um exemplo muito ruim seria um objeto que está contando de 1 a 100, expondo seu valor atual como uma referência mutável. Isso permite que um objeto de terceiros altere o valor de Current de forma que o valor possa estar fora dos limites esperados.

Isso é principalmente um problema com a exposição de objetos mutáveis. Expor estruturas ou objetos imutáveis ​​não é um problema, pois qualquer alteração nessas alterações altera uma cópia (geralmente por uma cópia implícita no caso de uma estrutura ou por uma cópia explícita no caso de um objeto imutável).

Usar uma metáfora que facilite ver a diferença.

Uma flor tem várias coisas únicas. Tem um Colore tem um número de pétalas (NumPetals). Se estou observando aquela flor, no mundo real, posso ver claramente sua cor. Posso então tomar decisões com base nessa cor. Por exemplo, se a cor é preta, não dê para a namorada, mas se a cor for vermelha, dê para a namorada. Em nosso modelo de objeto, a cor da flor seria exposta como um getter no objeto da flor. Minha observação dessa cor é importante para as ações que executarei, mas não afeta o objeto da flor. Eu não deveria ser capaz de mudar a cor dessa flor. Da mesma forma, não faz sentido ocultar a propriedade da cor. Uma flor geralmente não pode impedir as pessoas de observar sua cor.

Se eu pintar a flor, devo chamar o método ReactToDye (Color dyeColor) na flor, que mudará a flor de acordo com suas regras internas. Em seguida, posso consultar a Colorpropriedade novamente e reagir a qualquer alteração após a chamada do método ReactToDye. Seria errado modificar diretamente o Colorda flor e, se pudesse, a abstração se desintegraria.

Às vezes (com menos frequência, mas ainda com frequência suficiente), os setters são um projeto OO bastante válido. Se eu tiver um objeto Customer, é bastante válido expor um setter para o endereço deles. Se você chama isso setAddress(string address)ou ChangeMyAddressBecauseIMoved(string newAddress)simplesmente string Address { get; set; }é uma questão de semântica. O estado interno desse objeto precisa mudar e a maneira apropriada de fazer isso é definir o estado interno desse objeto. Mesmo se eu precisar de um registro histórico de endereços em que Customerele morou, posso usar o configurador para alterar meu estado interno adequadamente. Nesse caso, não faz sentido o Customerimutável e não há melhor maneira de alterar um endereço do que fornecer um setter para fazê-lo.

Não tenho certeza de quem está sugerindo que Getters e setters são ruins ou quebram paradigmas orientados a objetos, mas se o fizerem, provavelmente o estão fazendo em resposta a um recurso específico da linguagem que eles usam. Tenho a sensação de que isso surgiu da cultura Java "tudo é um objeto" (e possivelmente se estendeu a outras linguagens). O mundo .NET não tem essa discussão. Getters e Setters são um recurso de idioma de primeira classe que é usado não apenas por pessoas que escrevem aplicativos no idioma, mas também pela própria API do idioma.

Você deve ter cuidado ao usar getters. Você não deseja expor os dados incorretos e nem os dados da maneira errada (por exemplo, objetos mutáveis, referências a estruturas que podem permitir que um consumidor modifique o estado interno). Mas você deseja modelar seus objetos para que os dados sejam encapsulados de forma que seus objetos possam ser usados ​​por consumidores externos e protegidos contra uso indevido por esses mesmos consumidores. Muitas vezes, isso exigirá getters.

Para resumir: Getters e Setters são ferramentas válidas de design orientado a objetos. Eles não devem ser usados ​​de maneira tão liberal que todos os detalhes da implementação sejam expostos, mas você não deseja usá-los com moderação para que os consumidores de um objeto não possam usá-lo com eficiência.

Stephen
fonte
-1

O que é uma coisa, sem opiniões, que vai quebrar se eu usar getters ...

A manutenção quebrará.

A qualquer momento (devo dizer quase sempre), você oferece um incentivo, basicamente doa mais do que lhe foi pedido. Isso também significa que você precisa manter mais do que o solicitado, e assim reduz a capacidade de manutenção sem motivo real.

Vamos com o Collectionexemplo de @ candied_orange . Ao contrário do que ele escreve Collection , não deveria ter um getter. As coleções existem por motivos muito específicos, principalmente para iterar todos os itens. Essa funcionalidade não é uma surpresa para ninguém, portanto deve ser implementada no Collection, em vez de empurrar esse caso de uso óbvio para o usuário, usando ciclos for e getters ou outros enfeites.

Para ser justo, alguns limites fazer getters necessidade. Isso acontece se você realmente não sabe para que serão usados. Por exemplo, você pode obter programaticamente o rastreamento de pilha da Exceptionclasse Java hoje em dia, porque as pessoas queriam usá-lo por todos os tipos de razões curiosas que os escritores não imaginavam ou não podiam imaginar.

Robert Bräutigam
fonte
1
Contraexemplo. Considere uma função que precisa iterar dois Collections, simultaneamente, como em (A1, B1), (A2, B2), .... Isso requer uma implementação de "zip". Como você implementa "zip" se a função de iteração reversa é implementada em um dos dois Collection- como você acessa o item correspondente no outro?
rwong 5/05/19
@rwong O Collectiontem que implementar zipsozinho, dependendo de como a biblioteca é escrita. Caso contrário, você o implementa e envia uma solicitação de recebimento ao criador da biblioteca. Note que concordei que algumas fronteiras precisam de getters às vezes, meu problema real é que getters estão em toda parte hoje em dia.
Robert Bräutigam
Nesse caso, isso implica que a biblioteca precisa ter getters no Collectionobjeto, pelo menos para sua própria implementação de zip. (Ou seja, o getter tem que ter visibilidade pacote, pelo menos.) E agora você depender do criador da biblioteca aceitar o seu pedido puxar ...
rwong
Eu não te entendo direito. O Collectionobviamente pode acessar seu próprio estado interno, ou para ser mais preciso qualquer Collectioninstância pode acessar estado interno de qualquer outro. É do mesmo tipo, sem necessidade de getters.
Robert Bräutigam
Também te ouço, mas, novamente, qual é exatamente a melhor solução para os getters? Eu sei que está fora do escopo da questão.
Coolpasta 5/05/19