Qual é o ponto das propriedades?

11

Aqui estão alguns argumentos para propriedades e meus contra-argumentos:

Mais fácil de usar do que escrever métodos getter e setter

Os pares de métodos getter e setter são cheiros de código. Tornar mais fácil escrever isso é como tornar mais fácil a reprovação em um teste de matemática usando um formulário Scantron e preenchendo todos os 'C'. Objetos que contêm apenas estado, por persistência, não devem usar getters / setters e devem criar objetos imutáveis ​​no momento da persistência.

O que é importante para um consumidor de um objeto é o que ele faz, não como ele faz. Seu comportamento é o que faz; seu estado é como ele faz isso. Se você se preocupa com o estado de um objeto (exceto pela persistência, embora isso também interrompa o OO), você simplesmente não está fazendo POO e perdendo suas vantagens.

Eles fornecem uma indicação aproximada do desempenho para os consumidores

Isso é algo que pode mudar no futuro, para qualquer propriedade. Suponha que na versão 1.0, acessar o PropertyX simplesmente retorne um campo. Na liberação 1.5, se o campo for nulo, o PropertyX usa o padrão Objeto Nulo para criar um novo objeto nulo. Na versão 2.0, o campo está sendo validado ainda mais pelo método getter no PropertyX.

À medida que a propriedade se torna cada vez mais complexa, a indicação de desempenho do uso de uma propriedade parece cada vez menos verdadeira.

Eles são melhores que os campos públicos

Isso é verdade. Mas o mesmo acontece com os métodos.

Eles representam um aspecto fundamentalmente diferente de um objeto que um método, e todos os consumidores do objeto devem se preocupar com isso.

Tem certeza de que ambas as afirmações acima são verdadeiras?

Eles são mais fáceis de digitar, cara

Claro, digitar myObject.Lengthé mais fácil do que digitar myObject.Length(), mas isso não poderia ser corrigido com um pouco de açúcar sintático?


Por que usar métodos em vez de propriedades?

  • Sem garantias de desempenho. A API permanecerá verdadeira, mesmo que o método fique mais complexo. O consumidor precisará criar um perfil de seu código se estiver enfrentando problemas de desempenho e não confiar na palavra da API.

  • Menos para o consumidor pensar. Esta propriedade possui um setter? Um método certamente não.

  • O consumidor está pensando a partir de uma mentalidade OOP adequada. Como consumidor de uma API, estou interessado em interagir com o comportamento de um objeto. Quando vejo propriedades na API, ela se parece muito com o estado. De fato, se as propriedades fizerem muito, elas nem deveriam ser propriedades; na verdade, as propriedades em uma API SÃO como elas aparecem para os consumidores.

  • O programador da API pensará mais profundamente sobre métodos com valores de retorno e evitará modificar o estado do objeto nesses métodos, se possível. A separação de comandos das consultas deve ser aplicada sempre que possível.


Então, pergunto: por que usar propriedades em vez de métodos? A maioria dos pontos no MSDN são odores de código por si só e não pertencem a propriedades ou métodos.

(Esses pensamentos vieram a mim depois de pensar no CQS.)

xofz
fonte
5
+1. Propriedades são métodos com a sintaxe dos campos e isso simplesmente não faz sentido.
Nemanja Trifunovic 26/03
23
@ Nemanja Trifunovic: Faz todo o sentido se você escreveu type GetFoo() void SetFoo()dez mil vezes. Durante todo o meu tempo escrevendo código C #, nunca fui confundido com uma propriedade.
Ed S.
23
Parece-me que você já se decidiu. Qual é a questão?
Dean Harding
9
@ Nemanja Trifunovic: "Pegadores e levantadores geralmente são ruins" Você pode repetir isso quantas vezes quiser, mas não será verdade. Que tal explicar por que você acha que eles são ruins? No caso de SO travar devido à digitação do nome da propriedade em vez do nome da variável subjacente, é impossível perder um erro, pois ele trava o programa assim que você chama a propriedade e isso é muito raro. Quando isso acontece, sei exatamente o que fiz para causá-lo e o conserto em dois segundos. Eu não vejo o problema.
Ed S.
3
Só de passagem, para apontar para @NemanjaTrifunovic que o artigo Por que os métodos getter e setter são maus é bastante antigo , trata-se de java e destaca uma fraqueza de java : a fraqueza de não ter propriedades . (portanto, mostrando muitos detalhes de implementação) ... mordendo nossa cauda aqui. (que deve ser intitulado getters e setters são maus em java, porque nós não temos nenhum maldito bem pensado padrão sobre aqueles )
ZJR

Respostas:

44

Por que são "métodos contra propriedades"? Um método faz alguma coisa. Uma propriedade é, bem, um membro de um objeto. São coisas totalmente diferentes, embora dois tipos de métodos comumente escritos - getters e setters - correspondam às propriedades. Como comparar propriedades com métodos em geral não é significativo, presumo que você quis falar sobre getters / setters.

Os pares de métodos getter e setter são cheiros de código.

Não necessariamente, eu diria, mas de qualquer forma isso não é uma questão de getters / setters vs. propriedades, mas uma questão de se alguma delas deve ser usada. Observe também que, por exemplo, você pode deixar de fora a setXpeça, assim como criar propriedades somente leitura.

O que é importante para um consumidor de um objeto é o que ele faz, não como ele faz. Seu comportamento é o que faz; seu estado é como ele faz isso. Se você se preocupa com o estado de um objeto (exceto pela persistência, embora isso também interrompa o OO), você simplesmente não está fazendo POO e perdendo suas vantagens.

Uma atitude altamente questionável. Se a GUI quiser gerar dados mantidos por a DataStuffManagerImpl, precisará obter esse número de alguma forma (e não, colocar metade do aplicativo na classe de widget não é uma opção).

À medida que a propriedade se torna cada vez mais complexa, a indicação de desempenho do uso de uma propriedade parece cada vez menos verdadeira.

[Os métodos têm] Nenhuma garantia de desempenho. A API permanecerá verdadeira, mesmo que o método fique mais complexo. O consumidor precisará criar um perfil de seu código se estiver enfrentando problemas de desempenho e não confiar na palavra da API.

Em quase todos os casos, toda a lógica de validação, etc. ainda é efetivamente O (1), ou de outro modo, com custo negativo. Caso contrário, talvez você tenha ido longe demais e esteja na hora de mudar. E um getX()método também é geralmente tratado tão barato!

Claro, digitar myObject.Length é mais fácil do que digitar myObject.Length (), mas isso não pode ser corrigido com um pouco de açúcar sintático?

As propriedades são esse açúcar sintático.

Menos para o consumidor pensar. Esta propriedade possui um setter? Um método certamente não.

"Existe um levantador para este caçador?" Mesma diferença.

O programador da API pensará mais profundamente sobre métodos com valores de retorno e evitará modificar o estado do objeto nesses métodos, se possível. A separação de comandos das consultas deve ser aplicada sempre que possível.

Não sei o que você está tentando nos dizer aqui. Para propriedades, existe uma lei não escrita ainda mais forte para não causar efeitos colaterais.

ChrisF
fonte
3
+1, e não é uma lei não escrita. As diretrizes de uso de propriedade no MSDN estão escritas com muitos outros. Eu acho que o OP deveria passar por eles para deixar claro muitas dúvidas. E não consigo postar um link aqui, pois estou escrevendo isso no meu telefone, mas as diretrizes devem ser fáceis de encontrar.
Decyclone
@ delnan: Propriedades não são esse açúcar sintático. As propriedades podem ser tratadas como campos (elas podem ser usadas como um destino de atribuição, se tiverem um setter). Métodos não podem.
xofz 30/09/11
1
@ SamPearson: obj.x = ymapeia obj.setX(y)e obj.xmapeia para obj.getX(). Como isso é diferente?
1
@ SamPearson, você pode alterar a visibilidade de um criador de propriedades e de um criador de propriedades independentes um do outro. Eu uso isso o tempo todo com meus objetos do Entity Framework: meus setters estão protegidos (portanto, apenas o framework pode definir um valor). Portanto, é perfeitamente viável a dizer comprimento int = myObject.Length sem permitir myObject.Length = 10
Michael Brown
19

Os pares de métodos getter e setter são cheiros de código.

Essa é uma suposição defeituosa e completamente incorreta. Os métodos Get / Set são uma maneira de encapsular um membro de dados e não são de forma alguma um "cheiro de código". Eu realmente odeio a maneira como algumas pessoas usam o termo "cheiro de código", mas de qualquer maneira ...

Isso é algo que pode mudar no futuro, para qualquer propriedade. Suponha que na versão 1.0, acessar o PropertyX simplesmente retorne um campo. Na liberação 1.5, se o campo for nulo, o PropertyX usa o padrão Objeto Nulo para criar um novo objeto nulo. Na versão 2.0, o campo está sendo validado ainda mais pelo método getter no PropertyX.

À medida que a propriedade se torna cada vez mais complexa, a indicação de desempenho do uso de uma propriedade parece cada vez menos verdadeira.

Parece uma API mal projetada, não vejo como isso é culpa da sintaxe da propriedade.

As propriedades em C # eram simplesmente açúcar sintático para um padrão muito comum que tornava nossas vidas como programadores um pouco mais fáceis. No entanto, hoje em dia, se você deseja usar a ligação de dados, "deve" usar propriedades, portanto, agora elas são um pouco mais que o açúcar sintático. Acho que realmente não concordo com nenhum dos seus pontos e não entendo por que você não gosta de um recurso de linguagem que suporte diretamente um padrão comum.

Ed S.
fonte
1
Eu vou dar uma recompensa para chegar a um termo melhor do que o cheiro do código. Basta ler um livro sobre refatoração, onde é usado milhares de vezes. É como unhas em um quadro-negro.
JeffO 26/03
1
@ Jeff O: Sim, acho que as pessoas que parecem usar esse termo com mais frequência não têm muita experiência.
Ed S.
6
@ Jeff O e ​​@ Ed S: IME, "cheiro de código" tornou-se o termo usado pelas pessoas quando realmente querem dizer "não gosto, mas não tenho um motivo"
Steven Evers
3
@SnOrfus: Sim, ou quando eles têm visões "religiosas" que geralmente fazem pouco sentido na prática, como "um método nunca deve ter mais do que X número de linhas" , que por sua vez geralmente é apenas uma repetição de algo que lê em algum lugar.
Ed S.
1
O uso inadequado dos métodos getter / setter é um cheiro de código, mas também deve ser o uso inadequado de qualquer coisa . Mesmo quando as coisas têm casos de uso restritos, empregá-las para esses casos de uso não deve ser considerado um cheiro de código. A criação de levantadores para tudo não deve ser um hábito cego, mas não se deve ter medo de incluí-los quando apropriado. O que é necessário é equilibrar a utilidade para os clientes de poder mudar de estado em vez de descobrir no futuro o que o estado era anterior (fácil se o estado for imutável). Ambos são úteis, mas o código deve escolher um.
Supercat 24/02
10

Sua premissa está errada.

As propriedades não são de forma alguma um contrato para desempenho, implementação interna ou qualquer outra coisa.
Propriedades são pares de métodos especiais, que representam semanticamente um atributo, se você desejar. E, portanto, o único contrato é que uma propriedade se comporte como você esperaria que um atributo se comportasse.
Se eu pedir a cor de um objeto, não suponho se é obtido por um acesso simples a um campo ou se é calculado a tempo.
O ponto principal é ter a capacidade de expor o comportamento de um atributo usando métodos, enquanto é transparente para o consumidor da interface, esteja você usando um campo ou acessadores.

Ter atributos (e realmente ocultar sua implementação, como propriedades opostas a campos) é um recurso declarativo poderoso , que é a base para ter inspetores de objetos visuais e outra geração automática de visualizações, para ligação de dados e muitas outras coisas úteis. E o mais importante, ele também transporta claramente essas informações para seus colegas programadores.

back2dos
fonte
6

O consumidor está pensando a partir de uma mentalidade OOP adequada. Como consumidor de uma API, estou interessado em interagir com o comportamento de um objeto. Quando vejo propriedades na API, ela se parece muito com o estado. De fato, se as propriedades fizerem muito, elas nem deveriam ser propriedades; na verdade, as propriedades em uma API SÃO como elas aparecem para os consumidores.

Uma propriedade deve ser um estado. Se o código subjacente do setter ou getter for alterado para adicionar significativamente ao processamento necessário para definir ou obter o estado, na verdade não será mais uma propriedade e você deverá substituí-lo por métodos. Isso depende de você como desenvolvedor do código.

Colocar código demais (quanto depende demais) em um setter ou getter está errado, mas apenas porque é possível não é uma razão para descartar o padrão em todos os casos.

ChrisF
fonte
6

Uma coisa que está faltando e eu não sei se isso é devido à ignorância ou se você está intencionalmente ignorando esse detalhe, é que as propriedades SÃO métodos.

Quando você usa a sintaxe de propriedade do C #, o compilador silenciosamente cria métodos getter e setter com metadados que informam aos idiomas que entendem as propriedades como um recurso sintático de primeira classe para tratá-las como tal. Na verdade, esse é o açúcar sintático que você está pedindo. Algumas linguagens que podem ser executadas no CLR não escondem completamente esses detalhes de você (Boo, se a memória me servir e algumas implementações do Lisp), e você pode chamar explicitamente os getters e setters.

As propriedades ocasionalmente têm efeitos colaterais, como acionar eventos de notificação de alterações (INotifyPropertyChanged, por exemplo) ou marcar uma instância de uma classe como suja. É aqui que eles têm seu valor real, apesar de criá-los é um pouco mais trabalhoso (exceto no Boo, que possui macros que aceitam sintaxe).

Agora, a questão mais ampla é se os métodos getter e setter são, de fato, uma coisa boa. Existem claramente trocas; se você tiver métodos mutadores, seu código é inerentemente menos paralelizável, porque agora você precisa lidar com problemas de sincronização de threads. E é bem possível que você corra o risco de violar a Lei de Demeter usando métodos mutadores (sejam chamados de propriedades ou métodos getter / setter; são equivalentes), porque é muito conveniente fazê-lo.

Mas às vezes é a coisa certa a fazer. Às vezes, seu problema é pegar dados de alguma fonte, alterá-los um pouco, apresentar os dados atualizados ao usuário e salvar as alterações. Esse idioma é bem servido pelas propriedades. Como o artigo de Allen Holub diz, apenas porque getters e setters têm problemas não significa que você nunca deve usá-los. (Papagaio abstrato Guruspeak considerado prejudicial). Mesmo quando você segue a abordagem Classe / Responsabilidades / Colaboradores, ainda acaba expondo informações ou apresentações de informações a alguém; o objetivo é minimizar a área da superfície do emaranhado.

A vantagem das propriedades é que é muito fácil ter outro objeto tirando vantagem delas. A desvantagem das propriedades é que é muito fácil ter outro objeto tirando vantagem delas, e você não pode impedir isso facilmente.

A mutação de objeto faz sentido na camada do controlador, em, por exemplo, uma arquitetura MVC. Esse é o seu colaborador. Sua visão também é um colaborador, mas não deve estar mudando diretamente seus objetos, porque possui responsabilidades diferentes. A inserção de código de apresentação nos objetos de negócios também não é necessariamente a maneira correta de evitar getters / setters.

A equação muda um pouco se você usar abstrações funcionais, em vez de puras OO, que geralmente tornam as cópias de um objeto "registro" com algumas alterações bastante triviais, embora não gratuitas. E ei, se você está tentando obter garantias de desempenho, as propriedades geralmente são mais previsíveis do que a reconstrução lenta de uma coleção imutável.

JasonTrue
fonte
5

Outro motivo importante em meu livro para usar propriedades é que elas podem aumentar bastante a legibilidade.

account.setBalance(Account.getBalance()+deposit);

é claramente muito menos legível do que

account.Balance += deposit;
apoorv020
fonte
6
Exceto que o Balance não deve ser uma propriedade, porque certamente existe uma lógica comercial significativa associada à alteração (verifique cheque especial, cobrança de taxa de serviço, transação de registro etc.) Seu ponto de legibilidade é completamente válido se aplicado a um exemplo diferente ( Temperatura, BackgroundColour etc.)
Kate Gregory
9
Por que não account.Deposit (quantia)?
xofz
4
@ Sam Pearson: +1. Um exemplo perfeito de por que os getters / setters geralmente indicam um design ruim.
Nemanja Trifunovic 27/03
4

Você tem quase o ponto de vista religioso oposto a mim :)

Quando mudei de Delphi para Java, a falta de propriedades foi uma grande afronta para mim. Eu estava acostumado a declarar uma propriedade e apontá-la diretamente para uma variável privada ou escrever um getter & setter (protegido) e depois "encaná-los" na propriedade. Isso encapsulou a propriedade e controlou como ela deveria ser acessada de uma maneira clara e inequívoca. Você pode ter uma propriedade somente leitura que calcule o total quando acessado e a chame de "Total" e não "_getTotal ()" ou ballochs semelhantes. Isso também significava que você poderia restringir o acesso às propriedades, protegendo-as na classe base abstrata e movendo-as para público ou publicadas em subclasses.

Para mim, as propriedades são uma maneira mais natural e expressiva de definir e obter o estado do objeto. Confiar em convenções de codificação não forçadas é mais um "cheiro de código" do que qualquer coisa para a qual você esteja criticando as propriedades. Além disso, como outros disseram, apresentar um uso mal projetado de propriedades e usar suas falhas para tentar descartar o conceito de propriedades em geral é uma forma extremamente ruim. É possível que você tenha visto apenas o mau uso das propriedades e suponha que seja assim, suponho, mas você deve fazer mais pesquisas antes de se tornar dogmático demais.

mcottle
fonte
+1 Isso realmente é um uso real de uma propriedade. Ótima resposta. " Isso também significava que você poderia restringir o acesso às propriedades, tornando-as protegidas na classe base abstrata e depois movendo-as para o público ou publicadas em subclasses. "
Karthik Sreenivasan
O Delphi usa mal as propriedades ad nauseam. Você não classifica a lista, define sua sorted propriedade para true. Portanto, configurá-lo para falsefornece a lista original. : D Ou embaralha aleatoriamente? : D Ou o que for, é apenas estúpido. Além disso, é muito lento em comparação com um conjunto classificado adequado. As propriedades não são ruins, mas aprendi a usá-las com moderação (até o ponto de ficar bastante feliz com getter e setters; estou usando principalmente Java).
Maaartinus
1

Uma das razões pelas quais as propriedades foram introduzidas no Java Beans Framework foi permitir a integração com um IDE - você pode arrastar esses componentes para o IDE e editar as propriedades usando editores de propriedades.

(naquela época, eles eram apenas receptores e levantadores regulares - e eram definidos apenas pela convenção de nomenclatura - e isso realmente cheirava)

Atualmente, existem ainda mais casos em que as propriedades são acessadas e modificadas, não através de código regular - como durante a depuração.

Ophir Yoktan
fonte
1

Um outro ângulo - eles realmente vieram do VB. Lembre-se, nos dias sombrios do século XX, quando o .NET foi concebido, uma das principais ênfases foi a substituição fácil e fácil do VB, para que seus programadores de VB pudessem arrastar e soltar as coisas nos formulários da web. O VB tinha propriedades, então você precisava manter esse recurso para que as coisas fossem traduzidas corretamente.

Wyatt Barnett
fonte
1
Anders Heljsberg projetou C # (e algumas das IL) e também Delphi - que tinha propriedades.
Jesse C. Slicer
1

Há pelo menos dois propósitos para propriedades:

  • Eles são conceitualmente idênticos aos campos, mesmo que sejam implementados de maneira diferente. Um getter não deve alterar o estado do objeto e não deve ter efeitos colaterais. Um levantador só deve alterar o estado de maneiras conceitualmente semelhantes à modificação de um campo e não ter outros efeitos colaterais.

  • Eles são sintaticamente idênticos aos campos públicos (possivelmente somente leitura). Isso significa que um campo público pode ser alterado para uma propriedade sem interromper os chamadores no nível de origem.

dsimcha
fonte
Sim, mas observe a palavra "deveria". Não há nada nas propriedades que impeça que os getters tenham efeitos colaterais e, de fato, já vi vários casos em que esse foi o caso.
Nemanja Trifunovic 27/03
1
Alterar um campo público para uma propriedade vai quebrar a compatibilidade binária, o código consumindo terá que ser recompilados - embora não modificado que eu estou supondo que é o que você estava chegando :)
MattDavey
@MattDavey: Obrigado. Foi isso que eu quis dizer. Editado.
dsimcha