Quando justificadores e setters são justificados

175

Getters e setters são frequentemente criticados por não serem apropriados OO. Por outro lado, a maioria dos códigos OO que eu tenho possui extensores e setters.

Quando justificadores e setters são justificados? Você tenta evitar usá-los? Eles são usados ​​em geral?

Se seu idioma favorito possui propriedades (a minha possui), essas coisas também são consideradas getters e setters para esta pergunta. Eles são a mesma coisa do ponto de vista da metodologia OO. Eles apenas têm uma sintaxe melhor.

Fontes para a crítica Getter / Setter (algumas tiradas dos comentários para oferecer melhor visibilidade):

Para declarar a crítica simplesmente: Getters e Setters permitem que você manipule o estado interno dos objetos de fora do objeto. Isso viola o encapsulamento. Somente o próprio objeto deve se preocupar com seu estado interno.

E um exemplo de versão procedural do código.

struct Fridge
{
    int cheese;
}

void go_shopping(Fridge fridge)
{
     fridge.cheese += 5;
}

Versão do código do Mutator:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

Os getters e setters tornaram o código muito mais complicado sem permitir o encapsulamento adequado. Como o estado interno é acessível a outros objetos, não ganhamos muito adicionando esses getters e setters.

A questão foi discutida anteriormente no Stack Overflow:

Winston Ewert
fonte
21
Getters and setters are often criticized as being not proper OO- Citação, por favor.
Robert Harvey
45
@ Job, por que porque tem código? É uma boa pergunta e cheira a guerra santa se levada a sério.
Peter Turner
2
@Winston Ewert: "... a questão é se você deveria acessar os dados dentro da classe.": Bem, ninguém o obriga a implementar getters e setters para todas as variáveis ​​de membro; É por isso que você usa getters e setters em vez de variáveis ​​de membro público.
Giorgio
2
@Winston Ewert: Não vejo como a ausência de getters / setters resolveria esse problema: deve haver uma maneira de acessar todos os dados, caso contrário eles serão inúteis; é tarefa de um bom design decidir qual parte dos dados está acessível para qual parte do código. Se um é um mau designer, ele ou ela será assim com ou sem getters e setters. Apenas meus 2 centavos.
Giorgio

Respostas:

162

Ter getters e setters, por si só, não quebra o encapsulamento. O que quebra o encapsulamento é adicionar automaticamente um getter e um setter para cada membro de dados (todos os campos , em linguagem java), sem pensar em nada. Embora isso seja melhor do que tornar todos os membros de dados públicos, está apenas a um pequeno passo.

O objetivo do encapsulamento não é que você não consiga saber ou alterar o estado do objeto de fora do objeto, mas deve ter uma política razoável para fazê-lo.

  • Alguns membros de dados podem ser totalmente internos ao objeto e não devem ter getters nem setters.

  • Alguns membros de dados devem ser somente leitura, para que possam precisar de getters, mas não de setters.

  • Alguns membros de dados podem precisar ser mantidos consistentes entre si. Nesse caso, você não forneceria um setter para cada um, mas um método único para defini-los ao mesmo tempo, para que você possa verificar os valores quanto à consistência.

  • Alguns membros de dados podem precisar ser alterados apenas de uma certa maneira, como incrementados ou decrementados por um valor fixo. Nesse caso, você forneceria um método increment()e / ou decrement()método, em vez de um levantador.

  • No entanto, outros talvez precisem ser de leitura e gravação e teriam um getter e um setter.

Considere um exemplo de a class Person. Digamos que uma pessoa tenha um nome, um número de previdência social e uma idade. Digamos que não permitimos que as pessoas mudem seus nomes ou números de previdência social. No entanto, a idade da pessoa deve ser aumentada em 1 a cada ano. Nesse caso, você forneceria um construtor que inicializaria o nome e o SSN com os valores fornecidos e inicializaria a idade para 0. Você também forneceria um método incrementAge(), que aumentaria a idade em 1. Você também forneceria getters para todos os três. Nenhum setter é necessário neste caso.

Nesse design, você permite que o estado do objeto seja inspecionado de fora da classe e que ele seja alterado de fora da classe. No entanto, você não permite que o estado seja alterado arbitrariamente. Existe uma política que afirma efetivamente que o nome e o SSN não podem ser alterados e que a idade pode ser aumentada em 1 ano por vez.

Agora, digamos que uma pessoa também tenha um salário. E as pessoas podem mudar de emprego à vontade, o que significa que seu salário também mudará. Para modelar essa situação, não temos outra maneira senão fornecer um setSalary()método! Permitir que o salário seja alterado à vontade é uma política perfeitamente razoável nesse caso.

A propósito, no seu exemplo, eu daria à classe Fridgeos métodos putCheese()e takeCheese(), em vez de get_cheese()e set_cheese(). Então você ainda teria encapsulamento.


public class Fridge {
  private List objects;
  private Date warranty;

  /** How the warranty is stored internally is a detail. */
  public Fridge( Date warranty ) {
    // The Fridge can set its internal warranty, but it is not re-exposed.
    setWarranty( warranty );
  }

  /** Doesn't expose how the fridge knows it is empty. */
  public boolean isEmpty() {
    return getObjects().isEmpty();
  }

  /** When the fridge has no more room... */
  public boolean isFull() {
  }

  /** Answers whether the given object will fit. */
  public boolean canStore( Object o ) {
    boolean result = false;

    // Clients may not ask how much room remains in the fridge.
    if( o instanceof PhysicalObject ) {
      PhysicalObject po = (PhysicalObject)o;

      // How the fridge determines its remaining usable volume is a detail.
      // How a physical object determines whether it fits within a specified
      // volume is also a detail.
      result = po.isEnclosedBy( getUsableVolume() );
    }

     return result;
  }

  /** Doesn't expose how the fridge knows its warranty has expired. */
  public boolean isPastWarranty() {
    return getWarranty().before( new Date() );
  }

  /** Doesn't expose how objects are stored in the fridge. */
  public synchronized void store( Object o ) {
    validateExpiration( o );

    // Can the object fit?
    if( canStore( o ) ) {
      getObjects().add( o );
    }
    else {
      throw FridgeFullException( o );
    }
  }

  /** Doesn't expose how objects are removed from the fridge. */
  public synchronized void remove( Object o ) {
    if( !getObjects().contains( o ) ) {
      throw new ObjectNotFoundException( o );
    }

    getObjects().remove( o );

    validateExpiration( o );
  }

  /** Lazily initialized list, an implementation detail. */
  private synchronized List getObjects() {
    if( this.list == null ) { this.list = new List(); }
    return this.list;
  }

  /** How object expiration is determined is also a detail. */
  private void validateExpiration( Object o ) {
    // Objects can answer whether they have gone past a given
    // expiration date. How each object "knows" it has expired
    // is a detail. The Fridge might use a scanner and
    // items might have embedded RFID chips. It's a detail hidden
    // by proper encapsulation.
    if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
      throw new ExpiredObjectException( o );
    }
  }

  /** This creates a copy of the warranty for immutability purposes. */
  private void setWarranty( Date warranty ) {
    assert warranty != null;
    this.warranty = new Date( warranty.getTime() )
  }
}
Dave Jarvis
fonte
4
Por favor, não leve muito a sério o meu exemplo de geladeira. :) Um refrigerador de verdade deve ser um objeto contêiner, eu esperaria que ele soubesse como segurar objetos sem se preocupar com o que exatamente eles eram. Ou seja, seria como um ArrayList. Quanto ao que o torna um refrigerador, digamos que serialize objetos em disco quando armazenados, para que possam sobreviver a falhas do sistema. Está bem. O suficiente para levar o meu exemplo da geladeira a sério.
Winston Ewert
6
Mas a geladeira não deve saber as datas de validade, para que possa dizer que o queijo está estragado e deve ser jogado fora? :) Ok, temos que parar com isso! :)
Dima
10
Uma discussão bastante interessante sobre a lógica do refrigerador que você está discutindo aqui ...
Mason Wheeler
35
Haha, eu gostaria de ver o anúncio para isso: "É um novo tipo de geladeira: lança coisas para você quando tenta pegar algo que não está lá! Dessa forma, você só tenta uma vez! Você se preocupa com isso" encher a geladeira e deixe a geladeira se preocupar com comportamento ilegal! "
gablin
42
O exemplo está errado. Não deve haver um campo Age nem um método setAge (). A idade é uma função da Data de nascimento da Pessoa, em comparação com algum ponto no tempo. Embora pareça trivial, é exatamente isso que está errado com a prática moderna de mutabilidade total de objetos e outros designs ruins, como é visto pelos métodos get / set para campos privados, considerando cuidadosamente o que é realmente mutável, o que é um campo, o que o objeto deve saber sobre seus comportamentos e quais alterações de estado são realmente válidas (quais métodos setX destroem completamente).
Darrell Teague
41

A razão básica para getters e setters em Java é muito simples:

  • Você só pode especificar métodos , não campos, em uma interface.

Portanto, se você deseja permitir a passagem de um campo pela interface, precisará de um método de leitura e gravação. Estes são tradicionalmente chamados de getX e setX para o campo x.

user1249
fonte
44
Essa é uma limitação de idioma. A verdadeira questão é se devemos permitir que outros objetos manipulem esse estado.
Winston Ewert
3
@ Peter Turner, claramente nada impede que um idioma tenha interfaces que incluam propriedades. Nos bastidores, pode muito bem ser implementado como getter / setter, mas seria fácil adicionar suporte às definições de interface para propriedades.
Winston Ewert
2
@Winston, você precisará permitir que as aulas passem informações um para o outro para realmente fazer o trabalho. O que você sugeriria?
6
Um objeto deve fornecer uma interface de nível superior para ele. Getters e Setters tendem a ser uma interface de baixo nível. Por exemplo, suponha que você tenha uma classe que implementa uma árvore binária. Você pode ter funções como GetLeft (), GetRight (), GetValue () e GetKey () para navegar na árvore. Mas essa é a abordagem completamente errada. Sua classe de árvore binária deve fornecer operações como Localizar, Inserir, Excluir.
Winston Ewert
6
Para dar outro exemplo, considere uma peça de tetris. A peça tetris possui algum estado interno, como block_type, rotação, posição. Você poderia ter getters como GetBlockType (), GetRotation (), GetPosition (). Mas você realmente não deveria. O que você deve ter é um método GetSquares () que retorna uma lista de todos os quadrados ocupados por esta peça. Você também não deve ter itens como SetPosition () ou SetRotation (). Em vez disso, você deve ter operações como MoveLeft (), MoveRight (), Rotate (), Fall ().
Winston Ewert
20

Em http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and

Estilo JavaBean:

connection.setUser("dukie");
connection.setPwd("duke");
connection.initialize();

Estilo OO:

connection.connect("dukie","duke");

Bem, claramente prefiro a última abordagem; ele não sangra os detalhes da implementação, é mais simples e conciso, e todas as informações necessárias são incluídas na chamada do método, por isso é mais fácil acertar. Também prefiro definir membros privados usando parâmetros no construtor, sempre que possível.

Sua pergunta é: quando um getter / setter se justifica? Talvez quando seja necessária uma mudança de modo ou você precise interrogar um objeto para obter algumas informações.

myObject.GetStatus();
myObject.SomeCapabilitySwitch = true;

Ao pensar nisso, quando comecei a codificar em C #, escrevi muito código no estilo Javabeans ilustrado acima. Mas, à medida que ganhei experiência no idioma, comecei a definir mais os membros no construtor e a usar métodos que se pareciam mais com o estilo OO acima.

Robert Harvey
fonte
6
Por que o estilo "dar todos os argumentos como parâmetros" é OO?
5
Enquanto o seu "estilo OO" é bom para 2 ou 3 opções, eu preferiria o estilo JavaBean assim que chegar acima disso. Ter 20 métodos sobrecarregados para cada combinação possível de parâmetros apenas parece terrível
TheLQ
1
@TheLQ: C # 4.0 facilita isso ao permitir parâmetros opcionais e nomeados nas chamadas de construtor e método.
Robert Harvey
7
@TheLQ É para isso que serve o Builder com sintaxe fluente, veja, por exemplo, o MapMaker da Guava .
Maaartinus 6/08
5
@ Thorbjørn Ravn Andersen, eu diria que "fornecer todos os argumentos como parâmetros" é melhor no estilo OO do que "chamar setters JavaBean" porque um setter implica que está sendo definido um atributo subjacente, que por definição expõe detalhes internos. O uso do método connect (..) no exemplo não faz essa suposição; talvez você defina atributos de usuário e senha, talvez não. O importante é que você se concentre no conceito correto de OO: a mensagem "conectar".
Andres F.
13

Quando justificadores e setters são justificados?

Quando o comportamento "get" e "set" correspondem realmente ao comportamento do seu modelo, o que é praticamente nunca .

Qualquer outro uso é apenas uma trapaça, porque o comportamento do domínio comercial não é claro.

Editar

Essa resposta pode parecer irreverente, então deixe-me expandir. As respostas acima são na maioria corretas, mas focam nos paradigmas de programação do design de OO e alguns que perdem o quadro geral. Na minha experiência, isso leva as pessoas a pensar que evitar gettings e setters é uma regra acadêmica para linguagens de programação OO (por exemplo, as pessoas pensam que substituir getters por propriedades é grande)

De fato, é uma conseqüência do processo de design. Você não precisa entrar em interfaces, encapsulamentos e padrões, discutindo se isso quebra ou não esses paradigmas e o que é ou não uma boa programação OO. O único ponto que importa em última análise é que, se não houver nada no seu domínio que funcione assim, colocando-o em você, você não está modelando seu domínio.

A realidade é que é altamente improvável que qualquer sistema em seu espaço de domínio tenha getters e setters. Você não pode ir até o homem ou a mulher responsável pela folha de pagamento e simplesmente dizer "Defina este salário como X" ou "Consiga esse salário para mim" . Esse comportamento simplesmente não existe

Se você está colocando isso em seu código, não está projetando seu sistema para corresponder ao modelo do seu domínio. Sim, isso quebra as interfaces e o encapsulamento, mas esse não é o ponto. O ponto é que você está modelando algo que não existe.

Além disso, você provavelmente está perdendo uma etapa ou processo importante, porque provavelmente existe uma razão pela qual eu não posso simplesmente andar para pagar a folha e dizer definir esse salário para X.

Quando as pessoas usam getters e setters, elas tendem a empurrar as regras desse processo para o lugar errado. Isso está se afastando ainda mais do seu domínio. Usando o exemplo do mundo real, é como salário assumindo que a pessoa aleatória que entrou tem permissão para obter esses valores, caso contrário ele não estaria pedindo por eles. Não só não é assim que o domínio é, como também está mentindo sobre como é o domínio.

Cormac Mulhall
fonte
este não parece oferecer nada substancial sobre os pontos feitos e explicado em antes 17 respostas
mosquito
1
As outras respostas falam sobre objetos, interfaces e outros paradigmas de linguagens. O que é bom, mas não é a questão central. Getters e setters não são apenas ruins porque quebram algumas convenções de codificação, mas principalmente porque você quase nunca encontra esse comportamento no modelo real que está representando. Esse ponto tende a se perder na discussão sobre as melhores práticas de codificação.
Cormac Mulhall
O que você acha que a interface da folha de pagamento é se não for set/getsalário?
Winston Ewert
1
Se eles estiverem envolvidos em camadas de autorização e restritos a certas entidades externas, não serão getters e setters. Não estou dizendo que não há nenhum método no departamento de folha de pagamento que altere o salário, mas esse método deve estar alinhado com os processos internos em vigor na própria empresa. Por exemplo, a maioria das empresas define salário com base no contrato de funcionários, que é autorizado por um gerente. Se o salário do funcionário mudar, um novo contrato é estabelecido e um gerente deve assiná-lo. Portanto folha de pagamento deve esperar um objeto do contrato e algum objeto autorização para alterar folha de pagamento
Cormac Mulhall
3
Ou, dito de outra maneira, há uma grande diferença entre set_salary (new_salary, employee_id) e allowed_salary_update (employee_contract, authorising_manager). O processo deve modelar o processo de negócios internos
Cormac Mulhall
11

Como regra geral, getters e setters são uma má idéia. Se um campo não faz parte da interface e você o torna privado, tudo bem. Se fizer parte da interface e você a tornar pública, tudo bem. Mas se você torná-lo privado e depois se virar e torná-lo efetivamente público novamente, fornecendo um getter e um setter, você volta ao ponto em que começou, exceto que seu código está agora mais detalhado e ofuscado.

Obviamente, há exceções. Em Java, pode ser necessário usar interfaces. A biblioteca padrão Java possui requisitos de compatibilidade com versões anteriores tão extremas que superam as medidas normais de qualidade de código. É até possível que você esteja lidando com o caso lendário, mas raro, em que há uma boa chance de substituir um campo armazenado posteriormente pelo cálculo em tempo real sem interromper a interface. Mas essas são exceções. Getters e setters são um anti-padrão que precisa de justificativa especial.

rwallace
fonte
6
Um getter e um setter significam que o atributo, não o campo, faz parte da interface. Suponha que getBirthDate () e SetBirthDate () recebam "aaaa / mm / dd", mas o campo armazenado seja o número de dias desde 01/01/1000. Você pode alterar isso para 01/01/0001 e o getter e o setter manterão a interface igual. Especialmente porque 'público' significa publicamente lavável, variáveis ​​nunca devem ser públicas; sempre use um setter para validar o valor recebido, atualizar todos os campos relacionados, converter conforme necessário etc. Tente usar um getter caso o armazenamento interno seja alterado.
Andy Canfield
@AndyCanfield que é um pouco forte para dizer que público significa publicamente passível de ser lavado .. Isso é apenas se você programá-lo mal. Se você tiver um setter e o valor errado for enviado a ele, você poderá lançar uma exceção que você poderia chamar de lixeira do programa, mas será encerrada com um erro. valor, então você pode ter isso em mente e testá-lo. você pode dizer "ah, mas só preciso fazer um teste se usar um setter", mas talvez seu próprio código dê um valor ruim à variável ... então o setter pode não reduzir a sua tests.n com testes, ur prog não é "um lixo"
barlop
3

se o campo é acessível diretamente ou via método não é realmente importante.

Invariantes de classe (úteis) são importantes. E para preservá-los, às vezes precisamos não conseguir mudar algo de fora. Por exemplo. se tivermos a classe Square com largura e altura separadas, alterar uma delas fará com que ela se torne algo além de square. Então, precisamos do método changeSide Se fosse Retângulo, poderíamos ter setters / public field. Mas o setter do que testaria se seu maior que zero seria melhor.

E em linguagens concretas (por exemplo, java), existem razões pelas quais precisamos desses métodos (interfaces). E outro motivo para o método é a compatibilidade (fonte e binário). Portanto, é mais fácil adicioná-los e depois pensar se o campo público seria suficiente.

btw. Eu gosto de usar um valor imutável simples, segurando classes com campos finais públicos.

user470365
fonte
Essa é praticamente a única coisa que deve ser evitada. Ir de campo para propriedade / getter / setter é uma mudança radical na maioria dos idiomas.
MrDosu
2

Você pode alterar seus internos para o que for, mantendo as interfaces iguais. Se suas interfaces não variarem, elas codificadas não serão quebradas. Você ainda pode alterar seus internos conforme desejar.

George Silva
fonte
1
Estou surpreso que esta resposta seja tão baixa. Os getters e setters permitem que você faça mais no futuro (por exemplo, dispare um evento, faça mais validação de entrada, faça contabilidade interna) sem interromper sua API existente. Mesmo com código não público, menos APIs precisam ser alteradas, menos dependências a serem atualizadas e menos bugs introduzidos ao fazer essas atualizações.
AmadeusDrZaius
0

Minha abordagem é essa -

Quando espero me interessar pelos dados mais tarde, um getter / setter é justificado. Além disso, se a mudança está acontecendo, muitas vezes eu empurro os dados para um getter / setter.

Se for uma estrutura POD, deixo os slots disponíveis.

Em um nível mais abstrato, a questão é "quem gerencia os dados", e isso depende do projeto.

Paul Nathan
fonte
0

Se o uso de getters e setters parecer complicado, o problema pode ser a linguagem, não o próprio conceito.

Aqui está o código do segundo exemplo escrito em Ruby:

class Fridge
  attr_accessor :cheese
end

def go_shopping fridge
  fridge.cheese += 5
end

Observe que se parece muito com o primeiro exemplo em Java? Quando getters e setters são tratados como cidadãos de primeira classe, eles não são uma tarefa fácil de usar, e a flexibilidade adicionada às vezes pode ser um benefício real - por exemplo, poderíamos decidir retornar um valor padrão para queijo em uma geladeira nova:

class Fridge
  attr_accessor :cheese

  def cheese
    @cheese || 0
  end
end

É claro que haverá muitas variáveis ​​que não devem ser expostas publicamente. A exposição desnecessária de variáveis ​​internas tornará seu código pior, mas você dificilmente pode culpar os getters e setters.

Tobias Cohen
fonte
Isso é lindamente declarado. As funções do Builder foram adicionadas porque queremos criar objetos imutáveis ​​enquanto construímos gradualmente a receita: talvez se você adicionar adoçante artificial, não precise adicionar açúcar. Usando parâmetros nomeados, e mesmo com sobrecarga, é muito difícil criar um método para fazer tudo. E é claro que o java não possui parâmetros nomeados, portanto, mais uma razão pela qual as pessoas estão usando o padrão Builder.
YoYo
0

Considere uma Sizeclasse que encapsula largura e altura. Posso eliminar setters usando o construtor, mas como isso me ajuda a desenhar um retângulo Size? Largura e altura não são dados internos da classe; são dados compartilhados que devem estar disponíveis para os consumidores do Size.

Objetos consistem em comportamentos e estados - ou atributos. Se não houver estado exposto, apenas os comportamentos serão públicos.

Sem estado, como você classificaria uma coleção de objetos? Como você procuraria por uma instância específica de um objeto? Se você usa apenas construtores, o que acontece quando seu objeto tem uma longa lista de atributos?

Nenhum parâmetro de método deve ser consumido sem validação. Portanto, é preguiça de escrever:

setMyField(int myField){
    this.myField = myField;
}

Se você escrever dessa maneira, pelo menos se preparou para usar o setter para validação; é melhor do que um campo público - mas apenas por pouco. Mas, pelo menos, você tem uma interface pública consistente que pode retornar e aplicar regras de validação sem quebrar o código de seus clientes.

Getters, setters, propriedades, mutadores, chame-os como quiser, mas eles são necessários.

Dale
fonte
Mas, pelo menos, você tem uma interface pública consistente que pode retornar e aplicar regras de validação sem quebrar o código de seus clientes. Isso não é verdade. Adicionar regras de validação mais adiante pode muito bem "quebrar o código de seus clientes". Pegue uma intvariável de instância, por exemplo, e imagine que você decide adicionar uma regra de validação para aceitar apenas valores não negativos. O problema é que o código do seu cliente já pode contar com a possibilidade de configurá-lo para um valor negativo ...
jub0bs
0

Se getters e setters violam o encapsulamento e o verdadeiro OO, então estou seriamente com problemas.

Eu sempre senti que um objeto representa o que melhor vem à mente que você precisa.

Acabei de escrever um programa que gera Mazes em Java e tenho uma classe que representa "Maze Squares". Eu tenho dados nesta classe que representam coordenadas, paredes e booleanos etc.

Eu tenho que ter alguma maneira de alterar / manipular / acessar esses dados! O que faço sem getters e setters? Java não usa propriedades e definir todos os meus dados locais para essa classe como público é DEFINITIVAMENTE uma violação do encapsulamento e do OO.

Bryan Harrington
fonte
6
Aqui está a pergunta: se você tornasse todos esses campos públicos e parasse de usar os getters e setters, como o seu código seria diferente?
Winston Ewert #
Em teoria, não é. Por que fazer uma aula nesse ponto? O mesmo argumento poderia ser feito com qualquer coisa. Mas o post abaixo do meu parece ter dito isso de maneira mais elegante. (Getters e setters são uma maneira de entregar com segurança um valor a um objeto, ou recuperar um valor de objeto.) O post continua ..
Bryan Harrington
3
Eu apontaria: esse pôster acabou concordando comigo e postou outra resposta para esse efeito. Essencialmente, usar getters e setters é o mesmo que manipular os dados diretamente. Você realmente não ganha OOness fazendo isso. Para ser OO, você deve fornecer uma interface de nível superior aos dados.
Winston Ewert
4
Eu acho que a melhor maneira de descrever isso seria dizer que você deve projetar suas interfaces de fora para dentro, e não de dentro para fora. A interface que seu objeto fornece deve ser ditada pela maneira como o objeto é usado e não como ele é implementado. Portanto, não escreva getters e permita que objetos externos interpretem os dados. Descubra qual pergunta eles precisam ser respondidos e escreva um método que responda a essa pergunta. Não permita que objetos externos modifiquem o estado por um setter, descubra que tipo de manipulação eles precisam executar e escreva métodos que fazem isso.
Winston Ewert
2
Em alguns casos, Getters e Setters são o melhor método. Às vezes, eles são a melhor interface que você pode fornecer. No entanto, em muitos casos, eles não são. Em muitos casos, você está apenas vazando detalhes da implementação para outras classes.
Winston Ewert #
-1

Em primeiro lugar, existem amplamente dois tipos de objetos que comentarei, tipos de valor e serviço.

Os tipos de serviço nunca devem ter setters, quaisquer que sejam as dependências necessárias, não devem ser obtidas. A melhor maneira de passar dependências é através de um construtor ou fábrica, assim todas as instâncias são totalmente formadas desde o início, pura e simplesmente.

Os tipos de valor também devem ser imutáveis, por outro lado, há momentos em que isso não é prático, como um ORM, ou algum outro mapeamento, como de um widget para um objeto. Todos os outros tipos de valores que passam pelo sistema de uma camada ou parte para outra devem ser imutáveis ​​e não devem ter setters.

mP01
fonte
Eu sugeriria um terceiro tipo: um contêiner mutável, cujo objetivo é armazenar um ou mais valores; em muitos casos, não se espera que um contêiner tenha muito em termos de lógica ou validação. O código que precisa de um método para calcular seis números inteiros positivos pode passar um contêiner para seis números inteiros para o método que armazenará os resultados nele. A responsabilidade de garantir que os números sejam positivos geralmente deve recair sobre o chamador ou o método chamado, não sobre o contêiner.
precisa saber é
-1

Um Getter / Setter é justificado como qualquer outro método público. A justificativa é principalmente porque queremos fornecer uma interface para o mundo externo que defina como nossa classe interage com outras classes. Fazemos isso principalmente porque queremos reduzir o acoplamento entre entidades separadas. Reduzir o acoplamento é uma coisa boa por vários motivos:

  • Posso usar no meu código atual a mesma interface de classe, embora a classe tenha adicionado novos métodos (mas preservada a interface antiga)
  • Pode alterar a representação interna de uma classe sem afetar seus consumidores
  • Reduza a chance de erros: se você tornar seus dados internos privados, pode ter certeza de que o código externo não mexerá com seus dados internos
Ghita
fonte
-1

Sim, getters e setters é um antipadrão na programação orientada a objetos e nunca deve ser usado: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . Em poucas palavras, eles não se encaixam no paradigma orientado a objetos porque incentivam você a tratar um objeto como uma estrutura de dados. Qual é um grande equívoco.

yegor256
fonte
2
este não parece oferecer nada substancial sobre os pontos feitos e explicado em antes 18 respostas
mosquito
4
Também é um pouco forte para dizer nunca .
Winston Ewert 16/09
-4

Espero que tudo o que o IDE desenvolvido pela empresa que desenvolve sua linguagem de programação gera automaticamente não viole os "Princípios de Orientação a Objetos".

Dito isto, toda vez que você tiver uma variável de escopo público, use um getter e um setter e ficará com o ouro. Parece-me o elemento necessário do princípio do encapsulamento extremamente orientado a objetos - mesmo que pareça um monte de código indesejável.

A razão para usá-los é que o encapsulamento adequado ainda pode ocorrer e, desde que você abstraia a camada que permite que a pessoa que mexe com seu objeto sinta seu objeto, você pode levá-lo embora sem que ele saiba direito?

Basta dizer que uma casa dividida não suporta, um dos inquilinos da OO não se liga e você não pode servir ao encapsulamento e à otimização prematura.

Peter Turner
fonte
4
e o que exatamente eu ganhei adicionando muito código para chamar setFoo () e getFoo () toda vez que lida com a variável?
Winston Ewert
7
Aqui está a coisa, eu não acho que você tenha um encapsulamento. Você ainda está manipulando o estado do objeto de outros lugares. Você está apenas fazendo isso de forma mais detalhada. Para obter encapsulamento, você precisa centralizar a manipulação de valores na classe que possui esse valor. Qualquer outra coisa é apenas código processual nas roupas OO. (Nada necessariamente errado com isso, mas é o que é).
Winston Ewert
2
A vantagem do encapsulamento é que toda a lógica relacionada a valores específicos está em um único lugar (mais ou menos). Eu não entendo isso com getters e setters. Portanto, acho que não tenho muitos benefícios para eles.
Winston Ewert
1
No entanto, concordo que prefiro ter código com getters e setters do que manipular livremente os dados via acesso público. Dessa forma, eu posso pelo menos anexar a validação dos dados recebidos.
Winston Ewert 27/11
3
Eu certamente não sou fã de verbosidade. Mas minha objeção são realmente as pessoas que tornam suas variáveis ​​privadas e depois as chamam de getters e setters livremente, acabando praticamente sem diferença. Se você deseja usar getters / setters dentro da sua classe, tudo bem. A questão é por quê? O principal benefício que eu conheço é que você pode fazer alguma validação nos dados para detectar erros mais cedo. Isso é menos útil quando todo o código que manipula os dados está no mesmo local. Mas ainda pode ser útil. Idealmente, você tem um idioma que suporta propriedades e pode evitar a verbosidade.
Winston Ewert
-4

Eu pensei que teríamos respostas mais comuns aqui?

Os getters e setters geralmente são extremamente OOP (qualquer pessoa que esteja dizendo algo errado, é simples assim).

Embora você precise se lembrar de não ter engenheiro em excesso, nunca faça um getter ou setter que não seja necessário. Qualquer informação que você não utilize por outra classe, não deve ter nenhum getter ou setter.

Porém, a razão pela qual você não torna os campos públicos e, em vez disso, tem getters e setters é principalmente:

  • Não é possível fazer testes adequados usando campos. Getters / setters são muito melhores nesse sentido.

  • É impossível usar corretamente os campos em uma configuração de programação em tempo real. Getters / setters sincronizados é o caminho a percorrer.

  • O tópico da interface (já explicado, então não vou).

  • É mais fácil de usar ao reutilizar o sistema corretamente.

  • É muito mais difícil saber quais classes estão usando sua classe e o que será interrompido se você alterar um campo do que um getter / setter.

Portanto, a única vez em que você usa um campo público em vez de um getter / setter é quando você não faz um projeto oficial, mas apenas por diversão e não pode se incomodar com o getter / setter.

Skarion
fonte
2
+1 para testabilidade. Chocado que ninguém mencionou isso antes. Outro recurso útil das propriedades é depurá-las. (é muito mais fácil inserir um ponto de interrupção no código do que exigir pontos de interrupção de hardware / memória para os campos).
Mark H
9
A objeção a getters e setters é que eles costumam ser usados ​​para seguir a letra da lei OOP enquanto ignoram o espírito e a intenção. OOP diz que você não deve permitir que outros objetos mexam com seus internos. Se você definir getters e setters que permitem fazer isso de qualquer maneira, você acabará violando o OOP.
Winston Ewert 27/11
6
Concordo que existem muitos benefícios de getters e setters em campos públicos simples. No entanto, não estou claro como os testes são melhores com eles. Você poderia explicar?
Winston Ewert 27/11
4
@Skarion: Eu não concordo com sua resposta. Você parece apresentar duas alternativas: usar getters / setters ou tornar os campos públicos. Mas há uma terceira opção: não usar getters / setters nem expor campos! Por que você precisaria testar o estado de um campo interno? Você não deveria testar a API pública do seu objeto?
Andres F.