Eu estava lendo esta página , sobre quando os getters / setters são justificados, e o OP forneceu o seguinte exemplo de código:
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);
}
A resposta aceita declara:
A propósito, no seu exemplo, eu daria à classe
Fridge
os métodosputCheese()
etakeCheese()
, em vez deget_cheese()
eset_cheese()
. Então você ainda teria encapsulamento.
Como o encapsulamento é preservado renomeando-o de get / set para putCheese()
/ takeCheese()
Você obviamente está obtendo / configurando um valor, então por que não simplesmente deixá-lo como get / set?
Na mesma resposta, também afirma:
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.
Nesse caso, temos apenas uma variável, cheese
e você pode levar e devolver o queijo à geladeira, portanto, um par de get / set é justificado.
fonte
putCheese
adicionaria queijo ao refrigerador etakeCheese
o removeria - essas são abstrações orientadas a domínios (de nível superior), em vez de getters e setters de campos de objetos (que são abstrações de programação de computador (de baixo nível)).Respostas:
Eu acho que você está perdendo o ponto. Não está dizendo que você deve renomear o setter e o getter, mas ter métodos que adicionem e removem itens da geladeira. ie
Agora a variável privada está encapsulada. Não posso simplesmente defini-lo como quiser, só posso adicionar e remover fatias de queijo da geladeira usando os métodos, que por sua vez garantem que quaisquer regras de lógica de negócios de queijo que eu queira sejam aplicadas.
fonte
setCheese()
tem a mesma lógica no setter. De qualquer maneira, para mim, você está tentando ocultar o fato de estar usando um setter renomeando o método, mas obviamente seu getter / definindo algo.AddCheese(Integer.MAX_VALUE)
deve falhar, mas não irá.Getters e setters quebram o encapsulamento toda vez , por definição. O que se pode argumentar é que às vezes precisamos fazer isso. Com isso fora do caminho, aqui estão minhas respostas:
A diferença está na semântica, ou seja, o significado do que você escreve. Encapsulamento não é apenas proteger, mas esconder o estado interno. O estado interno nem deve ser conhecido fora, mas o objeto deve oferecer métodos relevantes aos negócios (às vezes chamados de "comportamento") para manipular / usar esse estado.
Assim,
get
eset
são termos técnicos e parecem ter nada a ver com o domínio "geladeira", ao mesmo tempoput
etake
pode realmente fazer algum sentido.No entanto , se faz
put
ou nãotake
faz sentido realmente depende dos requisitos e não pode ser objetivamente julgado. Veja o próximo ponto:Isso não pode ser objetivamente determinado sem mais contexto. Seu exemplo contém um
go_shopping()
método em outro lugar. Se é para isso queFridge
serve, do que não precisaget
ouset
, o que precisa éFridge.go_shopping()
. Dessa forma, você tem um método derivado dos requisitos, todos os "dados" necessários são locais e você tem um comportamento real , em vez de apenas uma estrutura de dados velada.Lembre-se, você não está construindo um genérico, reutilizável
Fridge
. Você está construindo um apenasFridge
para seus requisitos. Qualquer esforço gasto para torná-lo mais do que precisa é realmente um desperdício.fonte
Getters and setters break encapsulation every single time
- Isso é um pouco forte demais para o meu gosto. Os métodos (incluindo caçadores e caçadores) têm o mesmo objetivo que os portões de um concerto: permitem entrada e saída ordenada do local.public int getFoo()
, é quase impossível, na prática, mudar para outro tipo.Quase tudo isso mostra um mal-entendido fundamental do encapsulamento e como ele se aplica.
A resposta inicial de que você estava quebrando o encapsulamento está errada. Talvez seu aplicativo precise definir o valor do queijo na geladeira em vez de aumentar / diminuir ou adicionar / remover. Além disso, não é semântica, não importa como você a chama, se você precisar acessar e / ou alterar atributos, não quebrará o encapsulamento, fornecendo-os. Finalmente, o encapsulamento não se trata realmente de "ocultar", trata-se de controlar o acesso ao estado e aos valores que não precisam ser públicos ou manipulados fora da classe, ao mesmo tempo em que é concedido àqueles que deveriam e executando a tarefa disponibilizada internamente.
Um getter ou setter não quebra o encapsulamento quando há uma necessidade legítima de obter ou definir um valor. É por isso que os métodos podem ser tornados públicos.
Encapsulamento é manter os dados e os métodos que modificam esses dados diretamente juntos em um local lógico, a classe.
Neste caso em particular, é claramente necessário alterar o valor do queijo na aplicação. Independentemente de como isso é feito, via get / set ou add / remove, desde que os métodos estejam encapsulados na classe, você está seguindo o estilo orientado a objetos.
Para esclarecimento, darei um exemplo de como o encapsulamento é quebrado, fornecendo acesso, independentemente do nome do método ou da execução lógica.
Digamos que sua geladeira tenha uma "vida útil", apenas alguns carrapatos antes que a geladeira não esteja mais operacional (por uma questão de argumento, a geladeira não pode ser reparada). Logicamente, não há como um usuário (ou o restante do seu aplicativo) conseguir alterar esse valor. Deve ser privado. Seria visível apenas através, digamos, de um atributo público diferente conhecido como "isWorking". Quando a vida útil expirar, internamente, a geladeira estará funcionando como falsa.
A execução da contagem regressiva da vida útil e o acionamento do interruptor isWorking são todos internos à geladeira, nada fora poderia / deveria ser capaz de afetar o processo. O isWorking deve estar visível apenas, portanto, um getter não quebra o encapsulamento. No entanto, a adição de acessadores para elementos do processo de vida útil quebraria seu encapsulamento.
Como a maioria das coisas, a definição de encapsulamento não é literal, é relativa. Você deve conseguir ver o X fora da classe? Você deveria poder mudar Y? Tudo o que se aplica ao seu objeto está nesta classe ou a funcionalidade está espalhada por várias classes?
fonte
Não é apenas renomear um método. Os dois métodos funcionam de maneira diferente.
(Imagine isso em sua mente)
get_cheese e set_cheese expõe o queijo. O putCheese () e o takeCheese () mantêm o queijo oculto e se encarregam de gerenciá-lo e dar ao usuário uma maneira de lidar com isso. O observador não vê o queijo, apenas vê dois métodos para manipulá-lo.
fonte