Evite getters e setters, exibindo informações do usuário

10

fundo

Estou lendo o livro "Código Limpo" e, paralelamente, estou trabalhando em objetos calistênicos Kata como a conta bancária, e estou preso a essa regra:

A 9ª regra dos objetos calistênicos é que não usamos getter ou setters.

Parece bem divertido, e eu concordo com esse princípio. Além disso, na página 98-99 do Código Limpo, o autor explica que os getters / setters quebram a abstração e que não precisamos perguntar ao nosso objeto, mas precisamos informar ao objeto.

Isso faz todo o sentido em minha mente e concordo plenamente com esse princípio. O problema vem na prática.

Contexto

Por exemplo, estou tendo um aplicativo no qual preciso listar alguns usuários e exibir os detalhes do usuário.

Meu usuário é composto por:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

Problema

Como posso fazer ou o que posso fazer para evitar getters quando preciso exibir apenas uma informação simples ( e tenho que confirmar que não preciso de operação extra nesse campo específico ) para exibir o valor do Nome de maneira simples ( aleatório) suporte de saída?

O que aparece em minha mente

Uma solução é fazer:

user.getName().getFirstName().getStringValue()

O que é totatally terrível, quebrando muitas regras de objetos calistênicos e violando a Lei Deméter.

Outro seria algo como:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

Mas não me sinto confortável com essa solução, que parece apenas um "acessador de ordem superior", como contornar o getter / setter padrão com um método que visa apenas corresponder à lei de Demeter ...

Qualquer ideia ?

mfrachet
fonte

Respostas:

17

O equívoco comum sobre a idéia de evitar getters e setters é evitá-los em todos os lugares, o que é impossível quando você vem à superfície da sua arquitetura interagindo com o usuário.

Você deve evitar o uso de getters e setters na parte da lógica de negócios do seu aplicativo, onde os objetos devem ser protegidos usando agregados que fornecem contexto e os métodos devem atuar como comandos.

Para evitar getters e setters, você pode projetar uma solução semelhante à programação reativa , implementando o sistema de relatórios por meio de entidades observáveis, mas isso complica extremamente a arquitetura e não faz sentido no nível CRUD do seu aplicativo, mesmo que o design seja realmente bom para interfaces de usuário.

Se você deve considerar o uso de getters / setters depende inteiramente da parte do aplicativo em que você está trabalhando atualmente. Se a sua preocupação com a interface com o usuário usando getters for completamente boa, para a lógica de negócios, onde você executaria parte de um código com base em um valor recuperado por meio de um getter, não tanto (isso grita que a lógica deveria estar realmente encapsulada dentro a classe em que você está chamando o getter).

Além disso, a lei do demeter não se trata de contar pontos, mas apenas de separar uma classe que fornece contexto, usando getters na classe para obter seus componentes aos quais você não deve ter acesso por conta própria.

Se você acha que sua interface com o usuário está indo muito fundo nos seus modelos de negócios, considere a introdução de modelos de exibição em seu sistema, sendo responsável por transformar partes específicas de modelos em representações visuais.

Andy
fonte
Ok, penso nessa sugestão como um mapeador entre minha entidade de domínio, para um DTO personalizado para minha camada de apresentação que teria alguns acessadores, certo?
Mfrachet
@ Margin Muito, sim.
Andy Andy
Todos os sons desta cascata material realmente bom e suave, Obrigado pela resposta;)
mfrachet
2

Uma direção a pensar seria fornecer uma função-membro de formatação genérica de strings, em vez de fornecer acesso aos dados brutos. Algo assim:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

Veja que, com essa abordagem, você não está restrito apenas a fornecer os dados completos, como pode ser, pode fornecer meios para transformar os dados de maneira conveniente e significativa. Por exemplo, você pode precisar fazer truques com maiúsculas e minúsculas:

String accountName = user.formatDescription("$(firstname).$(lastname)");

Você também pode definir alguns formatos comumente usados, possivelmente complexos, uma vez, por exemplo, por exemplo

String fullAddress = user.formatDescription(User.kAddressFormat);

A vantagem dessa abordagem é que ela mantém as seqüências individuais internas da Userclasse, enquanto fornece uma funcionalidade significativamente maior ao código de chamada. No entanto, a desvantagem é que você precisa implementar o mecanismo de modelagem no formatDescription()qual haverá algumas linhas de código.

Como tal, isso pode ser um exagero total: nunca esqueça que os princípios de programação são apenas diretrizes. E sempre que seguir outro princípio viola o princípio do KISS, é melhor fazê-lo da maneira mais simples. Portanto, a menos que você tenha pelo menos alguma necessidade de um membro dessa formatação, eu não me incomodaria em implementá-lo por uma questão de simplicidade, usando a abordagem baseada em acessador.

cmaster - restabelece monica
fonte
5
Isso, no entanto, parece uma violação do SRP para mim. É realmente responsabilidade de um Userobjeto analisar e compilar / interpretar uma linguagem de modelos?
Jörg W Mittag
@ JörgWMittag Não necessariamente. Como eu disse, o princípio do KISS tem precedência. E eu disse em nenhum lugar que a Userclasse precisa implementar essa funcionalidade. Se eu tivesse apenas duas classes que precisavam dessa funcionalidade, você poderia apostar em eu fatorar o mecanismo de substituição de modelo em sua própria classe. Isso deve ser um exemplo de como você pode elevar a abstração que Userfornece a um nível em que na verdade é mais do que apenas um contêiner de dados. E eu acredito que é isso que é evitar os acessadores: fazer POO em vez de lidar com vários structs.
cmaster - restabelecer monica
Você sabe que o KISS é totalmente subjetivo e objetivo do SRP? O KISS não diz nada sobre o que fazer. E o que é "Simples" para você pode não ser "simples" para mim. Vejo uma diferença real na qualidade ao discutir com o KISS ou SRP.
oopexpert