Por que usar getters e setters / accessors?


1544

Qual é a vantagem de usar getters e setters - que apenas obtêm e configuram - em vez de simplesmente usar campos públicos para essas variáveis?

Se getters e setters estão fazendo algo além do simples get / set, eu posso descobrir isso rapidamente, mas não sou 100% claro sobre como:

public String foo;

é pior do que:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Considerando que o primeiro leva muito menos código padrão.


6
@Dean J: Duplicate com muitas outras perguntas: stackoverflow.com/search?q=getters+setters
Asaph

8
Obviamente, ambos são igualmente ruins quando o objeto não precisa que uma propriedade seja alterada. Prefiro tornar tudo privado e, em seguida, adicionar getters, se útil, e setters, se necessário.
Tordek 14/10/09

26
Google "acessores são maus"
OMG Pôneis

34
"Acessores são ruins" se você escrever código funcional ou objetos imutáveis. Se você estiver escrevendo objetos mutáveis ​​com estado, eles são bastante essenciais.
Christian Hayter

Respostas:


982

Na verdade, existem muitas boas razões para considerar o uso de acessadores em vez de expor diretamente os campos de uma classe - além do argumento do encapsulamento e facilitar as alterações futuras.

Aqui estão algumas das razões pelas quais estou ciente:

  • Encapsulamento de comportamento associado à obtenção ou configuração da propriedade - isso permite que funcionalidades adicionais (como validação) sejam adicionadas mais facilmente mais tarde.
  • Ocultando a representação interna da propriedade enquanto expõe uma propriedade usando uma representação alternativa.
  • Isolando sua interface pública da mudança - permitindo que a interface pública permaneça constante enquanto a implementação muda sem afetar os consumidores existentes.
  • Controlando a semântica da vida útil e do gerenciamento de memória (descarte) da propriedade - particularmente importante em ambientes de memória não gerenciada (como C ++ ou Objective-C).
  • Fornecer um ponto de interceptação de depuração para quando uma propriedade muda em tempo de execução - depurar quando e onde uma propriedade foi alterada para um valor específico pode ser bastante difícil sem isso em alguns idiomas.
  • Interoperabilidade aprimorada com bibliotecas projetadas para operar contra getter / setters de propriedades - Mocking, Serialization e WPF vêm à mente.
  • Permitir que os herdeiros alterem a semântica de como a propriedade se comporta e é exposta substituindo os métodos getter / setter.
  • Permitindo que o getter / setter seja transmitido como expressões lambda em vez de valores.
  • Os getters e setters podem permitir diferentes níveis de acesso - por exemplo, o get pode ser público, mas o conjunto pode ser protegido.

60
+1. Apenas para adicionar: Permitir carregamento lento. Permitindo cópia na gravação.
NewbiZ

6
@ bjarkef: Eu acredito que os publicmétodos de acesso causam duplicação de código e expõem informações. Os acessadores públicos não são necessários para o empacotamento (serialização). Em algumas linguagens (Java), os publicacessadores get não podem ter o tipo de retorno alterado sem interromper as classes dependentes. Além disso, acredito que eles vão contra os princípios da OO. Veja também: stackoverflow.com/a/1462424/59087
Dave Jarvis

15
@sbi: Uma coisa que é comprada usando um configurador de propriedades, mesmo em uma estrutura bem projetada, é a capacidade de um objeto notificar outro quando uma propriedade é alterada.
Supercat 23/08/12

22
@ supercat: No entanto, geralmente não estou promovendo dados públicos. A notificação de outros objetos também pode ser feita a partir de métodos reais, fornecendo uma abstração significativa em um mero recipiente de dados com (mais ou menos) campos de dados públicos. Em vez de plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();eu quero dizer plane.takeOff(alt). Quais campos de dados internos precisam ser alterados para colocar o avião no takingOffmodo não são das minhas preocupações. E que outros objetos ( breaks) o método notifica que também não quero saber.
SBI

8
@ BenLee: Eu realmente não sei mais o que dizer. "Acessadores" é apenas um sinônimo de "getters / setters", e nos meus dois primeiros comentários expliquei por que esses são um abuso do termo "OOP". Se você precisar alcançá-lo e manipular o estado diretamente, não é um objeto no sentido de POO desse termo.
S12

480

Como daqui a duas semanas (meses, anos), quando você perceber que seu levantador precisa fazer mais do que apenas definir o valor, também perceberá que a propriedade foi usada diretamente em 238 outras classes :-)


84
Estou sentado e olhando para um aplicativo de linha de 500 mil onde nunca foi necessário. Dito isto, se for necessário uma vez, começará a causar um pesadelo de manutenção. Bom o suficiente para uma marca de seleção para mim.
Dean J

20
Só posso invejar você e seu aplicativo :-) Dito isso, isso realmente depende da sua pilha de software também. O Delphi, por exemplo (e C # - eu acho?) Permite que você defina propriedades como cidadãos de primeira classe, onde eles podem ler / escrever um campo diretamente inicialmente, mas - caso necessário - faça isso também através de métodos getter / setter. Mucho conveniente. Java, infelizmente, não - para não mencionar o padrão javabeans, que força você a usar getters / setters também.
ChssPly76 14/10/09

14
Embora esse seja realmente um bom motivo para o uso de acessadores, muitos ambientes de edição e editores agora oferecem suporte para refatoração (no IDE ou como suplementos gratuitos), o que reduz um pouco o impacto do problema.
LBushkin 14/10/09

62
soa como pré-amadurecer otimização
cmcginty

41
A pergunta que você precisa fazer quando se pergunta se deve implementar getters e setters é: Por que os usuários de uma classe precisariam acessar as entranhas da classe? Realmente não importa se eles fazem isso diretamente ou são protegidos por uma fina pseudo camada - se os usuários precisam acessar detalhes da implementação, isso é um sinal de que a classe não oferece uma abstração suficiente. Veja também este comentário .
SBI

358

Um campo público não é pior que um par getter / setter que não faz nada, exceto retornar o campo e atribuir a ele. Primeiro, é claro que (na maioria dos idiomas) não há diferença funcional. Qualquer diferença deve estar em outros fatores, como manutenção ou legibilidade.

Uma vantagem freqüentemente mencionada dos pares getter / setter, não é. Há uma alegação de que você pode alterar a implementação e seus clientes não precisam ser recompilados. Supostamente, os setters permitem adicionar funcionalidades como validação posteriormente e seus clientes nem precisam saber sobre isso. No entanto, adicionar validação a um levantador é uma alteração em suas condições prévias, uma violação do contrato anterior , que era, simplesmente, "você pode colocar qualquer coisa aqui e pode obter a mesma coisa posteriormente no levantador".

Então, agora que você quebrou o contrato, alterar todos os arquivos da base de código é algo que você deve querer fazer, não evitar. Se você evitá-lo, está assumindo que todo o código assumiu que o contrato para esses métodos era diferente.

Se esse não fosse o contrato, a interface permitiria que os clientes colocassem o objeto em estados inválidos. Esse é exatamente o oposto do encapsulamento. Se esse campo não podia realmente ser definido para nada desde o início, por que a validação não estava lá desde o início?

Esse mesmo argumento se aplica a outras supostas vantagens desses pares de passagem / coleta de coleta: se você decidir posteriormente alterar o valor que está sendo definido, está quebrando o contrato. Se você substituir a funcionalidade padrão em uma classe derivada, além de algumas modificações inofensivas (como log ou outro comportamento não observável), estará quebrando o contrato da classe base. Isso é uma violação do princípio da substituibilidade de Liskov, que é visto como um dos princípios da OO.

Se uma classe tem esses getters e setters burros para todos os campos, então é uma classe que não tem invariantes, nenhum contrato . Esse design é realmente orientado a objetos? Se tudo o que a classe tem são esses getters e setters, é apenas um detentor de dados burros, e os detentores de dados burros devem parecer com detentores de dados burros:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Adicionar pares getter / setter de passagem a essa classe não agrega valor. Outras classes devem fornecer operações significativas, não apenas operações que os campos já fornecem. É assim que você pode definir e manter invariantes úteis.

Cliente : "O que posso fazer com um objeto desta classe?"
Designer : "Você pode ler e escrever várias variáveis."
Cliente : "Oh ... legal, eu acho?"

Existem razões para usar getters e setters, mas se essas razões não existirem, criar pares getter / setter em nome de deuses falsos de encapsulamento não é uma coisa boa. Os motivos válidos para obter getters ou setters incluem as coisas frequentemente mencionadas como as possíveis alterações que você pode fazer posteriormente, como validação ou diferentes representações internas. Ou talvez o valor deva ser legível pelos clientes, mas não gravável (por exemplo, lendo o tamanho de um dicionário); portanto, um getter simples é uma boa opção. Mas essas razões devem estar presentes quando você faz a escolha, e não apenas como algo potencial que você pode querer mais tarde. Esta é uma instância do YAGNI ( você não vai precisar disso ).


13
Ótima resposta (+1). Minha única crítica é que foram necessárias várias leituras para descobrir como "validação" no parágrafo final diferia de "validação" nos primeiros (o que você descartou no último caso, mas promoveu no primeiro); o ajuste da redação pode ajudar nesse sentido.
Lightness Races in Orbit -

14
Essa é uma ótima resposta, mas, infelizmente, a era atual esqueceu o que é "ocultação de informações" ou para que serve. Eles nunca leram sobre imutabilidade e em sua busca pelo mais ágil, nunca desenharam o diagrama de transição de estado que definia quais eram os estados legais de um objeto e, portanto, o que não eram.
Darrell Teague

2
Uma observação importante é que getters são muito mais úteis que setters. Um getter pode retornar um valor calculado ou um valor computado em cache. Tudo que um levantador pode fazer é validar e alterar o privatecampo. Se uma classe não possui criadores, é fácil torná-la imutável.
Raedwald

7
Acho que você não sabe o que é uma classe invariável. Se é uma estrutura não trivial, significa praticamente que ela tem invariáveis ​​para defender e simplesmente não é possível projetá-la sem aqueles em mente. "Houve um erro, um membro foi atualizado errado." também se parece com "Uma atualização de membro violou os invariantes de classe". Uma classe bem projetada não permite que o código do cliente viole seus invariantes.
R. Martinho Fernandes

5
+1 para 'titulares mudos de dados devem se parecem com os detentores de dados mudos' Infelizmente, todo mundo parece projetar tudo em torno de detentores de dados mudos nos dias de hoje, e muitas estruturas até mesmo exigir isso ...
Joeri Hendrickx

93

Muitas pessoas falam sobre as vantagens de quem recebe e recebe, mas eu quero bancar o advogado do diabo. No momento, estou depurando um programa muito grande, em que os programadores decidiram criar tudo getters e setters. Pode parecer bom, mas é um pesadelo de engenharia reversa.

Digamos que você esteja pesquisando centenas de linhas de código e se depare com isso:

person.name = "Joe";

É um pedaço de código lindamente simples até você perceber que é um criador. Agora, você segue esse configurador e descobre que ele também define person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName e chama person.update (), que envia uma consulta ao banco de dados etc. onde seu vazamento de memória estava ocorrendo.

Compreender um pedaço de código local à primeira vista é uma propriedade importante de boa legibilidade que os getters e os setters tendem a quebrar. É por isso que tento evitá-los quando posso e minimizar o que eles fazem quando os uso.


8
Sim. Atualmente refatorando uma grande base de código, e isso tem sido um pesadelo. Os getters e setters fazem muito, incluindo chamar outros getters e setters muito ocupados que acabam reduzindo a legibilidade a nada. A validação é um ótimo motivo para o uso de acessadores, mas usá-los para fazer muito mais do que isso parece remover qualquer benefício potencial.
Fadecomic

31
Este é um argumento contra o açúcar sintático, não contra os levantadores em geral.
29413 Phil

6
Verdadeiro e verdadeiro, mas, além disso, aponta como o motivo pelo qual os criadores de propriedades individuais abrem a porta para estados inválidos sem absolutamente nenhum remédio para garantir a integridade de qualquer objeto que permita que a abstração vaze.
Darrell Teague

"É um pedaço de código lindamente simples até você perceber que é um setter" - ei, era o post original sobre Java ou sobre C #? :)
Honza Zidek

Eu concordo completamente com a legibilidade. É totalmente explícito o que está acontecendo quando person.name = "Joe";é chamado. Não há nenhum problema no caminho das informações, o destaque da sintaxe mostra que é um campo e a refatoração é mais simples (não é necessário refatorar dois métodos e um campo). Segundo, todos os ciclos cerebrais desperdiçados que pensam "getIsValid ()" ou deveriam ser "isValid ()" etc. podem ser esquecidos. Não consigo pensar em uma única vez em que fui salvo de um bug por um getter / setter.
Will

53

Existem muitas razões. O meu favorito é quando você precisa alterar o comportamento ou regular o que pode definir em uma variável. Por exemplo, digamos que você tenha um método setSpeed ​​(int speed). Mas você quer que você possa definir apenas uma velocidade máxima de 100. Você faria algo como:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Agora, e se EM TODA PARTE do seu código você estivesse usando o campo público e percebesse que precisava do requisito acima? Divirta-se procurando todos os usos do campo público em vez de apenas modificar o seu setter.

Meus 2 centavos :)


62
Caçar todos os usos do campo público não deve ser tão difícil. Torne-o privado e deixe que o compilador os encontre.
18719 Nathan Fellman

12
isso é verdade, é claro, mas por que torná-lo mais difícil do que foi projetado para ser. A abordagem get / set ainda é a melhor resposta.
Hardryv

28
@ Nathan: Encontrar outros usos não é o problema. Mudar todos eles é.
Graeme Perrow

22
@GraemePerrow ter que alterá-los todos é uma vantagem, não um problema :( E se você tivesse um código que assumisse que a velocidade poderia ser superior a 100 (porque, você sabe, antes de quebrar o contrato, poderia!) ( while(speed < 200) { do_something(); accelerate(); })
R. Martinho Fernandes

29
É um exemplo MUITO ruim! Alguém deve ligar: myCar.setSpeed(157);e depois de algumas linhas speed = myCar.getSpeed();E agora ... desejo a você uma depuração feliz ao tentar entender o porquê speed==100quando deveria ser157
Piotr Aleksander Chmielowski

53

Em um mundo puro, orientado a objetos, getters e setters são um terrível anti-padrão . Leia este artigo: Getters / Setters. Mal. Período . Em poucas palavras, eles incentivam os programadores a pensar em objetos como estruturas de dados, e esse tipo de pensamento é puramente processual (como em COBOL ou C). Em uma linguagem orientada a objetos, não há estruturas de dados, mas apenas objetos que expõem o comportamento (não atributos / propriedades!)

Você pode encontrar mais informações sobre eles na Seção 3.5 de Objetos elegantes (meu livro sobre programação orientada a objetos).


7
Getters e setters sugerem um modelo de domínio anêmico.
Raedwald

7
Ponto de vista interessante. Mas, na maioria dos contextos de programação, precisamos de estruturas de dados. Tomando o exemplo "Dog" do artigo vinculado. Sim, você não pode alterar o peso de um cachorro do mundo real definindo um atributo ... mas a new Dog()não é um cachorro. É um objeto que contém informações sobre um cachorro. E para esse uso, é natural poder corrigir um peso gravado incorretamente.
Stephen C

3
Bem, eu lhe digo que os programas mais úteis não precisam modelar / simular objetos do mundo real. IMO, isso não é realmente sobre linguagens de programação. É sobre o que escrevemos programas.
Stephen C

3
Mundo real ou não, Yegor está completamente certo. Se o que você tem é realmente um "Struct" e não precisa escrever nenhum código que faça referência a ele pelo nome, coloque-o em uma hashtable ou outra estrutura de dados. Se você precisar escrever um código para ele, coloque-o como membro de uma classe e coloque o código que manipula essa variável na mesma classe e omita o setter & getter. PS. embora eu compartilhe principalmente o ponto de vista de yegor, acredito que os beans anotados sem código são estruturas de dados um tanto úteis - também getters às vezes são necessários, setters nunca deveriam existir.
Bill K

1
Eu me empolguei - toda essa resposta, embora correta e relevante, não aborda a questão diretamente. Talvez devesse dizer "Ambos os setters / getters E variáveis ​​públicas estão erradas" ... Para ser absolutamente específico, os setters e as variáveis ​​públicas graváveis ​​nunca devem ser usadas, enquanto os getters são praticamente os mesmos que as variáveis ​​finais públicas e, ocasionalmente, são um mal necessário mas nenhum é muito melhor que o outro.
Bill K

38

Uma vantagem dos acessadores e mutadores é que você pode executar a validação.

Por exemplo, se foofosse público, eu poderia defini-lo facilmente nulle, em seguida, alguém poderia tentar chamar um método no objeto. Mas não está mais lá! Com um setFoométodo, eu poderia garantir que isso foonunca foi definido null.

Acessores e mutadores também permitem o encapsulamento - se você não vê o valor uma vez definido (talvez seja definido no construtor e depois usado pelos métodos, mas nunca deveria ser alterado), nunca será visto por ninguém. Mas se você pode permitir que outras classes vejam ou alterem, você pode fornecer o acessador e / ou o mutador adequados.


28

Depende do seu idioma. Você marcou isso como "orientado a objetos" em vez de "Java", então gostaria de salientar que a resposta do ChssPly76 depende da linguagem. No Python, por exemplo, não há razão para usar getters e setters. Se você precisar alterar o comportamento, poderá usar uma propriedade, que envolve um getter e um setter em torno do acesso básico ao atributo. Algo assim:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

2
Sim, eu disse isso em um comentário abaixo da minha resposta. Java não é a única linguagem a usar getters / setters como muleta, assim como o Python não é a única linguagem capaz de definir propriedades. O ponto principal, no entanto, ainda permanece - "propriedade" não é o mesmo "campo público".
ChssPly76 14/10/09

1
@jcd - de maneira alguma. Você está definindo sua "interface" (API pública seria um termo melhor aqui) expondo seus campos públicos. Feito isso, não há como voltar atrás. As propriedades NÃO são campos porque fornecem um mecanismo para interceptar tentativas de acesso a campos (roteando-os para métodos, se eles estiverem definidos); isto é, no entanto, nada mais que açúcar de sintaxe sobre os métodos getter / setter. É extremamente conveniente, mas não altera o paradigma subjacente - a exposição de campos sem controle sobre o acesso a eles viola o princípio do encapsulamento.
21710 ChrysPly76 #

14
@ ChssPly76 - eu discordo. Eu tenho tanto controle quanto se fossem propriedades, porque posso torná-las propriedades sempre que preciso. Não há diferença entre uma propriedade que usa getters e setters padrão, e um atributo bruto, exceto que o atributo bruto é mais rápido, porque utiliza o idioma subjacente, em vez de chamar métodos. Funcionalmente, eles são idênticos. A única maneira de o encapsulamento ser violado é se você acha que os parênteses ( obj.set_attr('foo')) são inerentemente superiores aos sinais de igual ( obj.attr = 'foo'). Acesso público é acesso público.
jcdyer

1
@jcdyer tanto controle, sim, mas não tanto a legibilidade, os outros muitas vezes, erradamente, que obj.attr = 'foo'apenas define a variável sem qualquer outra coisa acontecendo
Timo Huovinen

9
@TimoHuovinen Como isso é diferente de um usuário em Java, assumindo que obj.setAttr('foo')"apenas define a variável sem que nada aconteça"? Se é um método público, então é um método público. Se você o usar para obter algum efeito colateral, e for público, será melhor poder contar com tudo funcionando como se apenas esse efeito colateral pretendido tivesse acontecido (com todos os outros detalhes de implementação e outros efeitos colaterais, uso de recursos, qualquer que seja , oculto das preocupações do usuário). Isso não é absolutamente diferente com o Python. A sintaxe do Python para obter o efeito é apenas mais simples.
ely

25

Bem, eu só quero acrescentar que, mesmo que algumas vezes sejam necessários para o encapsulamento e a segurança de suas variáveis ​​/ objetos, se queremos codificar um programa orientado a objetos real, precisamos parar de sobrecarregar os acessórios , porque às vezes dependemos muito neles quando não é realmente necessário e isso torna quase o mesmo como se publicássemos as variáveis.


24

Obrigado, isso realmente esclareceu meu pensamento. Agora, aqui estão (quase) 10 (quase) boas razões para NÃO usar getters e setters:

  1. Quando você perceber que precisa fazer mais do que apenas definir e obter o valor, basta tornar o campo privado, o que informará instantaneamente onde você o acessou diretamente.
  2. Qualquer validação realizada apenas pode ser livre de contexto, o que raramente ocorre na prática.
  3. Você pode alterar o valor que está sendo definido - esse é um pesadelo absoluto quando o chamador passa um valor que eles [horror de choque] querem que você armazene COMO ESTÁ.
  4. Você pode ocultar a representação interna - fantástico, para garantir que todas essas operações sejam simétricas, certo?
  5. Você isolou sua interface pública de alterações sob as planilhas - se você estava projetando uma interface e não tinha certeza se o acesso direto a algo estava bom, então deveria ter continuado a projetar.
  6. Algumas bibliotecas esperam isso, mas não muitos - objetos de reflexão, serialização e simulação, todos funcionam bem com campos públicos.
  7. Herdando essa classe, você pode substituir a funcionalidade padrão - em outras palavras, você pode confundir REALMENTE os chamadores, não apenas ocultando a implementação, mas tornando-a inconsistente.

Os três últimos que eu estou saindo (N / A ou D / C) ...


11
Eu acho que o argumento crucial é que "se você estava projetando uma interface e não tinha certeza se o acesso direto a algo estava bom, então deveria ter continuado a projetar". Esse é o problema mais importante dos getters / setters: eles reduzem uma classe a um mero contêiner de (mais ou menos) campos públicos. No OOP real , no entanto, um objeto é mais do que um contêiner de campos de dados. Ele encapsula estado e algoritmos para manipular esse estado. O que é crucial nessa afirmação é que o estado deve ser encapsulado e apenas manipulado pelos algoritmos fornecidos pelo objeto.
SBI

22

Eu sei que é um pouco tarde, mas acho que há algumas pessoas interessadas em desempenho.

Eu fiz um pequeno teste de desempenho. Eu escrevi uma classe "NumberHolder" que, bem, contém um número inteiro. Você pode ler esse número inteiro usando o método getter anInstance.getNumber()ou acessando diretamente o número usando anInstance.number. Meu programa lê o número 1.000.000.000 de vezes, nos dois sentidos. Esse processo é repetido cinco vezes e a hora é impressa. Eu tenho o seguinte resultado:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(O tempo 1 é o caminho direto, o tempo 2 é o getter)

Veja bem, o getter é (quase) sempre um pouco mais rápido. Então eu tentei com diferentes números de ciclos. Em vez de 1 milhão, usei 10 e 0,1 milhões. Os resultados:

10 milhões de ciclos:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

Com 10 milhões de ciclos, os tempos são quase os mesmos. Aqui estão 100 mil (0,1 milhões) ciclos:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

Também com diferentes quantidades de ciclos, o getter é um pouco mais rápido que o normal. Espero que isso tenha ajudado.


3
Há uma sobrecarga "notável" com uma chamada de função para acessar a memória em vez de simplesmente carregar o endereço de um objeto e adicionar um deslocamento para acessar os membros. As chances são de que a VM tenha otimizado o seu getter de qualquer maneira. Independentemente disso, a sobrecarga mencionada não vale a pena perder todos os benefícios dos getters / setters.
Alex

16

Não use setters getters, a menos que seja necessário para sua entrega atual. Ou seja, não pense muito no que aconteceria no futuro, se alguma coisa a ser alterada for uma solicitação de mudança na maioria dos aplicativos de produção, sistemas.

Pense simples, fácil e adicione complexidade quando necessário.

Eu não tiraria proveito da ignorância dos proprietários de empresas com profundo conhecimento técnico, apenas porque acho correto ou gosto da abordagem.

Eu tenho um sistema massivo escrito sem setters de getters apenas com modificadores de acesso e alguns métodos para validar e executar a lógica de negócios. Se você absolutamente precisava do. Use qualquer coisa.


16

Usamos getters e setters:

  • para reutilização
  • executar validação em estágios posteriores da programação

Os métodos Getter e setter são interfaces públicas para acessar membros da classe privada.


Mantra de encapsulamento

O mantra de encapsulamento é tornar os campos privados e os métodos públicos.

Métodos Getter: Podemos obter acesso a variáveis ​​privadas.

Métodos de instalação: Podemos modificar campos particulares.

Mesmo que os métodos getter e setter não adicionem novas funcionalidades, podemos mudar de idéia mais tarde para criar esse método

  • Melhor;
  • mais seguro; e
  • Mais rápido.

Em qualquer lugar que um valor possa ser usado, um método que retorne esse valor pode ser adicionado. Ao invés de:

int x = 1000 - 500

usar

int x = 1000 - class_name.getValue();

Em termos leigos

Representação da classe "Pessoa"

Suponha que precisamos armazenar os detalhes disso Person. Este Persontem os campos name, agee sex. Fazer isso envolve a criação de métodos para name, agee sex. Agora, se nós precisamos criar uma outra pessoa, torna-se necessário criar os métodos para name, age, sextudo de novo.

Em vez de fazer isso, podemos criar um bean class(Person)com os métodos getter e setter. Portanto, amanhã podemos criar objetos desse Bean class(Person class)sempre que precisarmos adicionar uma nova pessoa (veja a figura). Portanto, estamos reutilizando os campos e métodos da classe bean, o que é muito melhor.


15

Passei um bom tempo pensando sobre o caso Java e acredito que os verdadeiros motivos são:

  1. Código para a interface, não a implementação
  2. As interfaces especificam apenas métodos, não campos

Em outras palavras, a única maneira de especificar um campo em uma interface é fornecendo um método para escrever um novo valor e um método para ler o valor atual.

Esses métodos são os infames getter e setter ....


1
Ok, segunda pergunta; no caso em que é um projeto em que você não está exportando fonte para ninguém e você tem total controle da fonte ... você está ganhando alguma coisa com getters e setters?
Dean J

2
Em qualquer projeto Java não trivial, você precisa codificar para interfaces para tornar as coisas gerenciáveis ​​e testáveis ​​(pense em modelos e objetos proxy). Se você usa interfaces, precisa de getters e setters.
Thorbjørn Ravn Andersen

15

Pode ser útil para carregamento lento. Digamos que o objeto em questão esteja armazenado em um banco de dados e você não deseja obtê-lo, a menos que precise. Se o objeto for recuperado por um getter, o objeto interno poderá ser nulo até que alguém o solicite; você poderá obtê-lo na primeira chamada para o getter.

Eu tinha uma classe de página base em um projeto que foi entregue a mim e estava carregando alguns dados de algumas chamadas de serviço web diferentes, mas os dados nessas chamadas de serviço web nem sempre eram usados ​​em todas as páginas filho. Os serviços da Web, por todos os benefícios, são pioneiros em novas definições de "lento", para que você não queira fazer uma chamada de serviço da Web se não for necessário.

Mudei de campos públicos para getters, e agora os getters verificam o cache e, se ele não estiver lá, chame o serviço da web. Portanto, com um pequeno agrupamento, muitas chamadas de serviço da Web foram impedidas.

Portanto, o getter me impede de tentar descobrir, em cada página filha, o que vou precisar. Se eu precisar, ligo para o getter, e ele vai encontrá-lo para mim, se ainda não o tiver.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

Então o getter chama o setter?
icc97

Eu adicionei um exemplo de código de como eu fiz isso no passado - essencialmente, você armazena a classe real em um membro protegido e, em seguida, retorna esse membro protegido no acessador get, inicializando-o se não for inicializado.
quillbreaker


13

Um aspecto que eu perdi nas respostas até agora, a especificação de acesso:

  • para membros, você tem apenas uma especificação de acesso para configurar e obter
  • para setters e getters, você pode ajustá-lo e defini-lo separadamente

13

Edição: Eu respondi a essa pergunta porque há um monte de gente aprendendo programação perguntando isso, e a maioria das respostas é muito tecnicamente competente, mas não é tão fácil de entender se você é um novato. Éramos todos novatos, então pensei em tentar uma resposta mais amigável para iniciantes.

Os dois principais são polimorfismo e validação. Mesmo que seja apenas uma estrutura de dados estúpida.

Digamos que temos essa classe simples:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Uma classe muito simples que contém a quantidade de líquido nela e qual é sua capacidade (em mililitros).

O que acontece quando eu faço:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

Bem, você não esperaria que isso funcionasse, certo? Você quer que haja algum tipo de verificação de sanidade. E pior, e se eu nunca especificasse a capacidade máxima? Oh querida, nós temos um problema.

Mas há outro problema também. E se as garrafas fossem apenas um tipo de recipiente? E se tivéssemos vários recipientes, todos com capacidades e quantidades de líquido cheias? Se pudéssemos fazer uma interface, deixamos o resto do nosso programa aceitar essa interface, e garrafas, bidão e todo tipo de coisa funcionariam de maneira intercambiável. Isso não seria melhor? Como as interfaces exigem métodos, isso também é uma coisa boa.

Nós acabaríamos com algo como:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

Ótimo! E agora apenas mudamos o Bottle para isso:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Vou deixar a definição de BottleOverflowException como um exercício para o leitor.

Agora observe como isso é mais robusto. Agora podemos lidar com qualquer tipo de contêiner em nosso código aceitando LiquidContainer em vez de Bottle. E como essas garrafas lidam com esse tipo de coisa pode ser diferente. Você pode ter garrafas que gravam seu estado no disco quando elas são alteradas ou garrafas que salvam em bancos de dados SQL ou o GNU sabe o que mais.

E tudo isso pode ter maneiras diferentes de lidar com várias gritos. O Bottle apenas verifica e se está transbordando lança uma RuntimeException. Mas isso pode ser a coisa errada a se fazer. (Existe uma discussão útil sobre o tratamento de erros, mas eu estou mantendo isso muito simples aqui de propósito. As pessoas nos comentários provavelmente apontarão as falhas dessa abordagem simplista.;)

E sim, parece que passamos de uma idéia muito simples para obter respostas muito melhores rapidamente.

Observe também que você não pode alterar a capacidade de uma garrafa. Agora está gravado em pedra. Você pode fazer isso com um int declarando-o final. Mas se essa fosse uma lista, você poderia esvaziá-la, adicionar coisas novas e assim por diante. Você não pode limitar o acesso a tocar as entranhas.

Há também a terceira coisa que nem todos abordaram: getters e setters usam chamadas de método. Isso significa que eles se parecem com métodos normais em qualquer outro lugar. Em vez de ter uma sintaxe específica estranha para DTOs e outras coisas, você tem a mesma coisa em todos os lugares.


2
Obrigado pela primeira explicação semi-decente de interfaces que li, sem referências a "controles remotos" ou "carros"
djvs

1
"Você pode ter garrafas que gravam seu estado em disco quando elas são alteradas ou garrafas que salvam em bancos de dados SQL". Mas de qualquer maneira, boa idéia para apresentá-lo!
Xerus

10

Em idiomas que não suportam "propriedades" (C ++, Java) ou exigem recompilação de clientes ao alterar campos para propriedades (C #), é mais fácil modificar os métodos get / set. Por exemplo, adicionar lógica de validação a um método setFoo não exigirá alteração da interface pública de uma classe.

Em idiomas que suportam propriedades "reais" (Python, Ruby, talvez Smalltalk?), Não há sentido em obter / definir métodos.


1
Gravando#. Se você adicionar funcionalidade a um get / set, isso não exigiria recompilação?
steamer25

@ steamer25: desculpe, digitado incorretamente. Eu quis dizer que os clientes da classe terão que ser recompilados.
31119 John Millikin

5
Adicionar lógica de validação a um método setFoo não exigirá alteração da interface de uma classe no nível do idioma , mas altera a interface real , também conhecida como contrato, porque altera as pré-condições. Por que alguém gostaria que o compilador não tratasse isso como uma mudança de ruptura quando é ?
R. Martinho Fernandes

@ R.MartinhoFernandes como se resolve esse problema "quebrado"? O compilador não pode dizer se está quebrando ou não. Isso é apenas uma preocupação quando você está escrevendo bibliotecas para outras pessoas, mas você está fazendo o zOMG universal ser dragões!
Phil

3
Exigir recompilação, conforme mencionado na resposta, é uma das maneiras pelas quais o compilador pode informá-lo sobre uma possível alteração de quebra. E quase tudo o que escrevo é efetivamente "uma biblioteca para os outros", porque não trabalho sozinho. Eu escrevo código que possui interfaces que outras pessoas no projeto usarão. Qual é a diferença? Inferno, mesmo que eu seja o usuário dessas interfaces, por que devo manter meu código com padrões de qualidade mais baixos? Não gosto de trabalhar com interfaces problemáticas, mesmo que eu as escreva.
R. Martinho Fernandes

6

Um dos princípios básicos do design de OO: encapsulamento!

Oferece muitos benefícios, um dos quais é possível alterar a implementação do getter / setter nos bastidores, mas qualquer consumidor desse valor continuará a funcionar enquanto o tipo de dados permanecer o mesmo.


23
A oferta de getters e setters de encapsulamento é ridiculamente fina. Veja aqui .
SBI

Se sua interface pública indicar que 'foo' é do tipo 'T' e pode ser definido como qualquer coisa, você nunca poderá mudar isso. Você não pode decidir fazê-lo do tipo 'Y', nem impor regras como restrições de tamanho. Portanto, se você tem um get / set público que não faz muito muito set / get, não está ganhando nada que um campo público não ofereça e tornando-o mais complicado de usar. Se você tiver uma restrição, como o objeto pode ser definido como nulo ou o valor precisar estar dentro de um intervalo, sim, seria necessário um método de conjunto público, mas você ainda apresentará um contrato ao definir esse valor que pode " alteração t
thecoshman

Por que um contrato não pode mudar?
29413 Phil

5
Por que as coisas devem continuar compilando se os contratos mudam?
R. Martinho Fernandes

5

Você deve usar getters e setters quando:

  • Você está lidando com algo que é conceitualmente um atributo, mas:
    • Seu idioma não possui propriedades (ou algum mecanismo semelhante, como os traços variáveis ​​de Tcl) ou
    • O suporte à propriedade do seu idioma não é suficiente para este caso de uso ou
    • As convenções idiomáticas do seu idioma (ou às vezes do seu framework) incentivam getters ou setters para este caso de uso.

Portanto, raramente é uma questão geral de OO; é uma pergunta específica de idioma, com respostas diferentes para idiomas diferentes (e diferentes casos de uso).


Do ponto de vista da teoria do OO, getters e setters são inúteis. A interface da sua classe é o que ela faz, não o seu estado. (Caso contrário, você escreveu a classe errada.) Em casos muito simples, onde o que uma classe faz é apenas, por exemplo, representar um ponto em coordenadas retangulares, * os atributos fazem parte da interface; getters e setters apenas obscurecem isso. Mas, em qualquer coisa, exceto em casos muito simples, nem os atributos, nem os getters e setters fazem parte da interface.

Dito de outra forma: se você acredita que os consumidores de sua classe nem deveriam saber que você tem um spamatributo, muito menos poder alterá-lo à vontade, então dar a eles um set_spammétodo é a última coisa que você deseja fazer.

* Mesmo para essa classe simples, talvez você não queira permitir a definição dos valores xe y. Se isso é realmente uma classe, não deveria ter métodos como translate,rotate , etc.? Se é apenas uma aula porque seu idioma não possui registros / estruturas / tuplas nomeadas, isso não é realmente uma questão de OO…


Mas ninguém nunca faz o projeto geral de OO. Eles estão fazendo design e implementação em um idioma específico. E em alguns idiomas, getters e setters estão longe de serem inúteis.

Se o seu idioma não tiver propriedades, a única maneira de representar algo que é conceitualmente um atributo, mas na verdade é computado, ou validado etc. é através de getters e setters.

Mesmo que seu idioma tenha propriedades, pode haver casos em que sejam insuficientes ou inapropriados. Por exemplo, se você deseja permitir que as subclasses controlem a semântica de um atributo, em idiomas sem acesso dinâmico, uma subclasse não poderá substituir uma propriedade computada por um atributo.

Quanto ao "e se eu quiser alterar minha implementação mais tarde?" question (que é repetido várias vezes com palavras diferentes na pergunta do OP e na resposta aceita): Se realmente é uma alteração pura na implementação e você começou com um atributo, pode alterá-lo para uma propriedade sem afetar a interface. A menos, é claro, que seu idioma não suporte isso. Portanto, esse é realmente o mesmo caso novamente.

Além disso, é importante seguir os idiomas da linguagem (ou estrutura) que você está usando. Se você escrever um belo código no estilo Ruby em C #, qualquer desenvolvedor experiente em C # que não seja você terá problemas para lê-lo, e isso é ruim. Algumas linguagens têm culturas mais fortes em torno de suas convenções do que outras. - e pode não ser coincidência que Java e Python, que estão em extremos opostos do espectro de como são os geters idiomáticos, possuam duas das culturas mais fortes.

Além dos leitores humanos, haverá bibliotecas e ferramentas que esperam que você siga as convenções e torne sua vida mais difícil se não o fizer. Conectar os widgets do Interface Builder a qualquer coisa, exceto propriedades ObjC, ou usar determinadas bibliotecas de simulação Java sem getters, está apenas dificultando sua vida. Se as ferramentas são importantes para você, não lute contra elas.


4

Do ponto de vista do design da orientação a objeto, ambas as alternativas podem ser prejudiciais à manutenção do código, enfraquecendo o encapsulamento das classes. Para uma discussão, você pode consultar este excelente artigo: http://typicalprogrammer.com/?p=23


3

Os métodos getter e setter são métodos acessadores, o que significa que geralmente são uma interface pública para alterar membros da classe privada. Você usa métodos getter e setter para definir uma propriedade. Você acessa os métodos getter e setter como propriedades fora da classe, mesmo que os defina dentro da classe como métodos. Essas propriedades fora da classe podem ter um nome diferente do nome da propriedade na classe.

Existem algumas vantagens em usar métodos getter e setter, como a capacidade de permitir a criação de membros com funcionalidades sofisticadas que você pode acessar como propriedades. Eles também permitem criar propriedades somente leitura e somente gravação.

Embora os métodos getter e setter sejam úteis, você deve tomar cuidado para não usá-los demais, pois, entre outros problemas, eles podem dificultar a manutenção do código em determinadas situações. Além disso, eles fornecem acesso à sua implementação de classe, como membros públicos. A prática de POO desencoraja o acesso direto às propriedades dentro de uma classe.

Ao escrever classes, você sempre é incentivado a tornar privadas o máximo possível de suas variáveis ​​de instância e adicionar métodos getter e setter adequadamente. Isso ocorre porque há várias vezes em que você não deseja permitir que os usuários alterem determinadas variáveis ​​nas suas classes. Por exemplo, se você possui um método estático privado que rastreia o número de instâncias criadas para uma classe específica, não deseja que um usuário modifique esse contador usando o código. Somente a declaração do construtor deve incrementar essa variável sempre que for chamada. Nessa situação, você pode criar uma variável de instância privada e permitir um método getter apenas para a variável counter, o que significa que os usuários podem recuperar o valor atual apenas usando o método getter e não poderão definir novos valores usando o método setter.


3

Código evolui . privateé ótimo para quando você precisa de proteção de membro de dados . Eventualmente, todas as classes devem ser uma espécie de "miniprogramas" que possuem uma interface bem definida, da qual você não pode se ferrar com os elementos internos .

Dito isso, o desenvolvimento de software não é sobre definir a versão final da classe como se você estivesse pressionando alguma estátua de ferro fundido na primeira tentativa. Enquanto você trabalha com ele, o código é mais parecido com o barro. Ele evolui à medida que você o desenvolve e aprende mais sobre o domínio do problema que está resolvendo. Durante o desenvolvimento, as classes podem interagir umas com as outras do que deveriam (dependência que você planeja levar em consideração), fundir-se ou separar-se. Então eu acho que o debate se resume a pessoas que não querem escrever religiosamente

int getVar() const { return var ; }

Então você tem:

doSomething( obj->getVar() ) ;

Ao invés de

doSomething( obj->var ) ;

Não é apenas getVar()visualmente barulhento, como também dá a ilusão de que gettingVar()é um processo mais complexo do que realmente é. Como você (como redator da turma) considera a santidade varé particularmente confuso para um usuário da sua turma se ela tiver um setstars - então parece que você está colocando esses portões para "proteger" algo que você insiste que é valioso, (a santidade de var), mas mesmo assim você concede vara proteção não vale muito pela capacidade de alguém simplesmente entrar e set varcom o valor que quiser, sem que você sequer espreite o que está fazendo.

Então, programo da seguinte maneira (assumindo uma abordagem do tipo "ágil" - ou seja, quando escrevo código sem saber exatamente o que estará fazendo / não tenho tempo ou experiência para planejar um conjunto elaborado de interface em estilo cascata):

1) Comece com todos os membros públicos para objetos básicos com dados e comportamento. É por isso que em todo o meu código de "exemplo" em C ++ você notará que eu estou usando, e structnão em classqualquer lugar.

2) Quando o comportamento interno de um objeto para um membro de dados se torna complexo o suficiente (por exemplo, ele gosta de manter um interno std::listem algum tipo de ordem), as funções do tipo acessador são gravadas. Como estou programando sozinho, nem sempre defino o membro privateimediatamente, mas em algum momento da evolução da classe o membro será "promovido" para um protectedou outroprivate .

3) As classes que são totalmente desenvolvidas e têm regras estritas sobre seus internos (ou seja, elas sabem exatamente o que estão fazendo e você não deve "foder" (termo técnico) com seus internos) recebem a classdesignação de membros particulares padrão, e apenas alguns membros selecionados podem participar public.

Acho que essa abordagem me permite evitar ficar sentado e escrever religiosamente getter / setters quando muitos membros de dados são migrados, trocados etc. durante os estágios iniciais da evolução de uma classe.


1
"... uma interface bem definida que você não pode simplesmente estragar com os internos de" e validação em setters.
Agi Hammerthief

3

Há um bom motivo para considerar o uso de acessadores: não há herança de propriedade. Veja o próximo exemplo:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Resultado:

0
0
4

3

Getters e setters são usados ​​para implementar dois dos aspectos fundamentais da Programação Orientada a Objetos, que são:

  1. Abstração
  2. Encapsulamento

Suponha que tenhamos uma classe Employee:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Aqui, os detalhes da implementação do Nome completo estão ocultos do usuário e não podem ser acessados ​​diretamente, ao contrário de um atributo público.


1
Para mim, ter toneladas de caçadores e caçadores que não fazem nada único é inútil. getFullName é uma exceção porque faz outra coisa. Ter apenas as três variáveis ​​públicas e manter getFullName facilitará a leitura do programa, mas ainda assim ocultará a coisa do nome completo. Geralmente eu estou completamente bem com getters e setters, se a. eles fazem algo único e / ou b. você só tem um, sim, você poderia ter uma final pública e tudo mais, mas não
FacelessTiger

1
O benefício disso é que você pode alterar os elementos internos da classe, sem alterar a interface. Digamos, em vez de três propriedades, você tinha uma - uma matriz de seqüências de caracteres. Se você estiver usando getters e setters, poderá fazer essa alteração e atualizar o getter / setters para saber que nomes [0] são o primeiro nome, nomes [1] são o meio, etc. Mas se você acabou de usar propriedades públicas , você também precisaria alterar todas as classes acessadas por Employee, porque a propriedade firstName que eles estavam usando não existe mais.
Andrew Hows

1
@AndrewHows do que eu vi na vida real, quando as pessoas mudam os elementos internos da classe, elas também mudam a interface e fazem uma grande refatoração de todo o código
Eildosa

2

Um outro uso (em idiomas que suportam propriedades) é que setters e getters podem sugerir que uma operação não é trivial. Normalmente, você deseja evitar fazer algo que seja computacionalmente caro em uma propriedade.


Eu nunca esperaria que um getter ou setter fosse uma operação cara. Nesses casos, use melhor uma fábrica: use todos os setters necessários e, em seguida, chame o método executeou o caro build.
Hubert Grzeskowiak

2

Uma vantagem relativamente moderna dos getters / setters é que facilita a navegação no código nos editores de código com tags (indexados). Por exemplo, se você quiser ver quem define um membro, pode abrir a hierarquia de chamadas do configurador.

Por outro lado, se o membro é público, as ferramentas não permitem filtrar o acesso de leitura / gravação ao membro. Então você tem que percorrer todos os usos do membro.


você pode fazer o clique certo> encontrar uso em um membro exatamente como em um getter / setter
Eildosa

2

Em uma linguagem orientada a objetos, os métodos e seus modificadores de acesso declaram a interface para esse objeto. Entre o construtor e os métodos acessador e mutador, é possível ao desenvolvedor controlar o acesso ao estado interno de um objeto. Se as variáveis ​​forem simplesmente declaradas públicas, não há como regular esse acesso. E quando estamos usando setters, podemos restringir o usuário para a entrada de que precisamos. Significa que o feed dessa variável passará por um canal adequado e o canal é predefinido por nós. Portanto, é mais seguro usar setters.


1

Além disso, isso é para "proteger o futuro" da sua turma. Em particular, mudar de um campo para uma propriedade é uma quebra da ABI; portanto, se você decidir mais tarde que precisa de mais lógica do que apenas "definir / obter o campo", precisará interromper a ABI, o que obviamente cria problemas para qualquer coisa mais já compilado contra sua classe.


2
Suponho que mudar o comportamento do getter ou setter não seja uma mudança de ruptura então. </sarcasm>
R. Martinho Fernandes

@ R.MartinhoFernandes nem sempre precisa ser. TBYS
Phil

1

Gostaria apenas de lançar a ideia da anotação: @getter e @setter. Com @getter, você poderá obj = class.field, mas não class.field = obj. Com o @setter, vice-versa. Com @getter e @setter, você poderá fazer as duas coisas. Isso preservaria o encapsulamento e reduziria o tempo ao não chamar métodos triviais em tempo de execução.


1
Seria implementado em tempo de execução com "métodos triviais". Na verdade, provavelmente não trivial.
29413 Phil

Hoje isso pode ser feito com um pré-processador de anotação.
Thorbjørn Ravn Andersen 07/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.