versus privado membros públicos na prática (o quão importante é o encapsulamento?) [fechado]

StackOverflow https://stackoverflow.com/questions/99688

  •  01-07-2019
  •  | 
  •  

Pergunta

Uma das maiores vantagens de programação orientada a objetos é o encapsulamento, e uma das "verdades" Nós (ou, pelo menos, eu tenho) foram ensinadas é que os membros devem sempre ser feitas privada e disponibilizados via acessores e modificadores métodos, garantindo, assim, a capacidade de verificar e validar as alterações.

Estou curioso, porém, o quão importante isso realmente é na prática. Em particular, se você tem um membro mais complicado (como uma coleção), ele pode ser muito tentador apenas torná-lo público, em vez de fazer um monte de métodos para obter as chaves, itens de adicionar / remover da coleção da coleção, etc.

Você segue a regra em geral? A sua mudança de resposta dependendo se do código escrito para si mesmo versus a ser utilizada por outras pessoas? Há razões mais sutis Estou em falta para este ofuscação?

Foi útil?

Solução

Depende. Esta é uma daquelas questões que devem ser decididas de forma pragmática.

Suponha que eu tinha uma classe para representar um ponto. Eu poderia ter getters e setters para as coordenadas X e Y, ou eu poderia simplesmente torná-los públicos e permitir o livre acesso de leitura / gravação aos dados. Na minha opinião, este é OK porque a classe é agir como um struct glorificado -. A coleta de dados com talvez algumas funções úteis anexados

No entanto, há uma abundância de circunstâncias em que você não deseja fornecer acesso completo aos seus dados interna e contam com os métodos fornecidos pela classe para interagir com o objeto. Um exemplo seria uma solicitação HTTP e resposta. Neste caso, é uma má idéia para permitir que qualquer pessoa para enviar qualquer coisa sobre o fio - deve ser processado e formatado pelos métodos de classe. Neste caso, a classe é concebida como um objeto real e não um armazenamento de dados simples.

Ele realmente se resume a existência ou não verbos (métodos) conduzir a estrutura ou se os dados faz.

Outras dicas

Como alguém ter que manter o código de vários anos, trabalhado por muitas pessoas no passado, é muito claro para mim que, se um atributo de membro é tornada pública, que eventualmente é abusado. Eu mesmo ouvi as pessoas que discordam com a idéia de assessores e modificadores, como isso ainda não é realmente viver de acordo com o propósito de encapsulamento, que está "escondendo o funcionamento interno de uma classe". É óbvio que é um tema controverso, mas a minha opinião seria "fazer cada variável de membro particular, pense primeiramente sobre o que a classe tem de do (métodos) em vez de como você' re vai deixar as pessoas mudam variáveis ??internas".

Sim, encapsulamento importa. Expondo a implementação subjacente faz (pelo menos) duas coisas erradas:

  1. mescla responsabilidades. Chamadores não devem precisar ou querer entender a implementação subjacente. Eles devem quer apenas a classe para fazer o seu trabalho. Ao expor a implementação subjacente, você está classe não está fazendo seu trabalho. Em vez disso, ele está apenas empurrando a responsabilidade para o chamador.
  2. os laços que para a implementação subjacente. Depois de expor a implementação subjacente, que está ligada a ele. Se você disser chamadores, por exemplo, há um debaixo coleção, você não pode facilmente trocar a coleção para uma nova implementação.

Estes (e outros) problemas aplicáveis ??independentemente de você dá acesso directo à implementação subjacente ou apenas duplicar todos os métodos subjacentes. Você deve estar expondo a implementação necessário, e nada mais. Manter os implementação marcas privadas do sistema global mais sustentável.

Eu prefiro manter os membros privado o maior tempo possível e só acessar em via getters, mesmo de dentro da mesma classe. Eu também tentar evitar setters como um primeiro projecto para promover a objetos de estilo valor, desde que isso é possível. Trabalhando com injeção de dependência muito muitas vezes você tem setters, mas não getters, como clientes deve ser capaz de configurar o objeto, mas (outros) não se saber o que está efectivamente configurado como este é um detalhe de implementação.

Saudações, Ollie

I tendem a seguir a regra muito rigorosa, mesmo quando é apenas o meu próprio código. Eu realmente gosto de Imóveis em C # para essa razão. Isso torna muito fácil de controlar o que valoriza é dado, mas você ainda pode usá-los como variáveis. Ou fazer o conjunto privado eo público get, etc.

Basicamente, ocultação de informações é sobre a clareza do código. Ele foi projetado para tornar mais fácil para alguém para estender seu código, e impedi-los de criar acidentalmente erros quando eles trabalham com os dados internos de suas classes. É baseado no princípio de que ninguém nunca lê comentários , especialmente aqueles com instruções nelas.

Exemplo: Eu estou escrevendo código que atualiza uma variável, e eu preciso ter certeza absoluta de que o Gui muda para refletir a mudança, a maneira mais fácil é adicionar um método de acesso (aka um "setter"), que é chamado em vez de atualizar os dados são atualizados.

Se eu fizer esse público de dados, e algo muda a variável sem passar pelo método Setter (e isso acontece cada palavrão tempo), então alguém terá de passar uma hora de depuração para descobrir por que as atualizações não são que está sendo exibido. O mesmo se aplica, em menor grau, aos dados "Como chegar". Eu poderia colocar um comentário no arquivo de cabeçalho, mas as probabilidades são de que ninguém vai lê-lo até que algo dá terrivelmente errado. Aplicá-la com meios privados que o erro não pode ser feito, porque ele vai aparecer como um erro de tempo de compilação facilmente localizado, em vez de um erro de tempo de execução.

A partir da experiência, as únicas vezes que você gostaria de tornar público um variável de membro, e deixar de fora os métodos get e set, é se você quer deixar absolutamente claro que a mudança terá nenhum efeito colateral; especialmente se a estrutura de dados é simples, como uma classe que simplesmente detém duas variáveis ??como um par.

Esta deve ser uma ocorrência bastante rara, como normalmente você deseja efeitos colaterais, e se a estrutura de dados que você está criando é tão simples que você não fizer isso (por exemplo, um emparelhamento), já haverá uma forma mais eficiente escrito um disponível em uma biblioteca padrão.

Com o que disse, para a maioria dos pequenos programas que são de uso único não-extensão, como as que você recebe na universidade, é mais "boa prática" do que qualquer coisa, porque você vai se lembrar ao longo de escrevê-las, e então você vai entregá-los em e nunca tocar o código novamente. Além disso, se você está escrevendo uma estrutura de dados como uma maneira de descobrir sobre como eles armazenam dados em vez de código de liberação, então há um bom argumento que getters e setters não ajuda, e vai ficar no caminho da experiência de aprendizagem .

É só quando você chegar ao local de trabalho ou um projeto grande, onde a probabilidade é que seu código será chamado para por objetos e estruturas escritos por pessoas diferentes, que se torna vital para fazer essas "lembretes" forte. Se é ou não é um projeto único homem é surpreendentemente irrelevante, pela simples razão de que "você seis semanas a partir de agora" é como pessoa diferente como um colega de trabalho. E "me há seis semanas", muitas vezes acaba por ser preguiçoso.

Um último ponto é que algumas pessoas são muito zelosos sobre ocultação de informações, e vai ficar irritado se os seus dados é desnecessariamente público. É melhor humor deles.

campos públicos C # Propriedades 'simulados'. Parece muito legal ea sintaxe realmente acelera criação desses / métodos estabelecidos get

Tenha em mente a semântica de chamar métodos em um objeto. A invocação de método é uma abstração muito alto nível que pode ser implementado meu compilador ou o sistema de tempo de execução em uma variedade de maneiras diferentes.

Se o objeto que é o método que você está chamando existe no mesmo mapa de processo / memória, em seguida, um método bem poderia ser otimizado por um compilador ou VM para acessar diretamente o membro de dados. Por outro lado, se o objeto vidas em outro nó em um sistema distribuído, então não há nenhuma maneira que você pode acessar diretamente os seus membros de dados internos, mas você ainda pode invocar seus métodos minha enviando-lhe uma mensagem.

Por codificação para interfaces de você pode escrever código que não importa onde existe o objeto de destino ou como seus métodos são invocados ou mesmo se está escrito na mesma língua.


No seu exemplo de um objeto que implementa todos os métodos de uma coleção, então certamente esse objeto realmente é uma coleção. então talvez isso seria um caso onde a herança seria melhor do que o encapsulamento.

É tudo sobre como controlar o que as pessoas podem fazer com o que você dar-lhes. Quanto mais controle você são os mais suposições que você pode fazer.

Além disso, theorectically você pode mudar a implementação subjacente ou algo assim, mas desde que para a maior parte é:

private Foo foo;
public Foo getFoo() {}
public void setFoo(Foo foo) {}

É um pouco difícil de justificar.

O encapsulamento é importante quando pelo menos um deles detém:

  1. Qualquer um, mas você vai usar sua classe (ou eles vão quebrar seus invariantes porque eles não ler a documentação).
  2. Quem não ler a documentação vai usar sua classe (ou eles vão quebrar seus invariantes cuidadosamente documentados). Note-se que esta categoria inclui você e dois anos-de-agora.
  3. Em algum ponto no futuro alguém vai herdar de sua classe (porque talvez uma necessidade de ação extras a serem tomadas quando o valor de um campo de mudanças, por isso não tem que ser um setter).

Se é só para mim, e utilizado em alguns lugares, e eu não vou herdar a partir dele, e os campos de mudança não vai invalidar quaisquer invariantes que a classe assume, só então I ocasionalmente, tornar público um campo.

A minha tendência é tentar fazer tudo o privado se possível. Isso mantém os limites do objeto tão claramente definidas quanto possível e mantém os objetos como dissociados possível. I como este, porque quando eu tenho que reescrever um objeto que eu remendada a primeira (segunda, quinta?) Tempo, mantém o dano contido a um número menor de objetos.

Se você casal a objetos com força suficiente, pode ser mais simples apenas para combiná-los em um objeto. Se você relaxar as restrições de acoplamento suficientes você está de volta à programação estruturada.

Pode ser que se você achar que um monte de seus objetos são apenas acessor funções, você deve repensar suas divisões de objeto. Se você não está fazendo todas as ações em que os dados possa pertencer, como parte de outro objeto.

Claro que, se você estiver escrevendo um algo como uma biblioteca que você quer como clara e nítida de uma interface possível para que outros possam programar contra ela.

Coloque a ferramenta para o trabalho ... recentemente eu vi algum código como este em minha base de código atual:

private static class SomeSmallDataStructure {
    public int someField;
    public String someOtherField;
}

E, em seguida, esta classe foi usado internamente para facilmente passando em torno de vários valores de dados. Nem sempre faz sentido, mas se você tiver apenas dados, sem métodos, e você não está expondo-lo aos clientes, acho que é um padrão bastante útil.

O uso mais recente que tive disso foi uma página JSP onde eu tinha uma tabela de dados que está sendo exibido, definido no topo de forma declarativa. Assim, inicialmente foi em múltiplas matrizes, uma matriz por campo de dados ... isso acabou no código ser bastante difícil de percorrer com campos não estar ao lado eachother na definição que seria exibido juntos ... então eu criei um simples classe, como acima que puxá-lo juntos ... o resultado foi código REALMENTE legível, muito mais do que antes.

Moral ... às vezes você deve considerar "aceita maus" alternativas se podem tornar o código mais simples e mais fácil de ler, contanto que você pensar sobre isso e considerar as conseqüências ... não aceitar cegamente tudo que você ouve .

Dito isto ... getters públicas e setters é praticamente equivalente a campos públicos ... pelo menos essencialmente, (há um pouco mais flexibilidade, mas ainda é um padrão ruim para aplicar a campo todos os que você tem).

Mesmo os java bibliotecas padrão tem alguns casos de campos públicos .

Quando faço objetos significativos são fácil para uso e mais fácil de manter .

Por exemplo: Person.Hand.Grab (howquick, howmuch);

O truque é não pensar em membros como valores simples mas objetos em si mesmos.

Eu diria que esta questão faz misturar-se o conceito de encapsulamento com 'escondendo informações'
(Isto não é uma crítica, uma vez que parece corresponder a uma interpretação comum da noção de 'encapsulamento')

No entanto, para mim, 'encapsulamento' é:

  • o processo de reagrupamento vários itens em um recipiente
  • o próprio recipiente reagrupando os itens

Suponha que você está projetando um sistema de contribuinte. Para cada contribuinte, você poderia encapsular a noção de criança para

  • uma lista das crianças que representam as crianças
  • um mapa do que leva em conta as crianças de pais diferentes
  • um objeto Children (não para crianças), que iria fornecer as informações necessárias (como o número total de crianças)

Aqui você tem três diferentes tipos de encapsulamentos, 2 representados por recipiente de baixo nível (lista ou mapa), um representado por um objeto.

Ao tomar essas decisões, você não

  • fazer que o encapsulamento público ou protegido ou privado: que a escolha de 'ocultação de informações' ainda está a ser feita
  • fazer uma completa abstração (você precisa para refinar os atributos de objeto Crianças e você pode decidir criar um objeto Criança, que iria manter apenas as informações relevantes do ponto de vista de um sistema de contribuinte)
    Abstração é o processo de escolha de quais atributos do objeto são relevantes para o seu sistema, e que deve ser completamente ignorado.

Assim, meu ponto é:
Essa pergunta pode sido intitulado:
versus privado membros públicos na prática (o quão importante é informações esconderijo ?)

Apenas meus 2 centavos, no entanto. I perfeitamente respeitar isso pode-se considerar encapsulamento como um processo que inclui a decisão ocultação de informação '.

No entanto, eu sempre tentar diferenciar 'abstração' - 'encapsulamento' -. 'Esconder informações ou visibilidade'

@VonC

Você pode achar a Organização Internacional de Normalização do "Modelo de Referência do Open Distributed Processing", uma leitura interessante. Ele define: "Encapsulation:. A propriedade de que a informação contida em um objeto só é acessível através de interações nas interfaces suportadas pelo objeto"

Eu tentei fazer um caso por ser informação esconderijo de uma parte crítica dessa definição aqui: http://www.edmundkirwan.com/encap/s2.html

Saudações,

Ed.

I encontrar lotes de getters e setters para ser um código cheiro que a estrutura do programa não é bem desenhado. Você deve olhar para o código que usa esses getters e setters, e olhar para a funcionalidade que realmente deve ser parte da classe. Na maioria dos casos, os campos de uma classe deve ser detalhes particulares de implementação e somente os métodos dessa classe pode manipulá-los.

Tendo ambos os getters e setters é igual ao público campo ser (quando os getters e setters são triviais / gerado automaticamente). Às vezes pode ser melhor apenas para declarar o público campos, de modo que o código será mais simples, a menos que você precisa polimorfismo ou um quadro requer métodos get / set (e você não pode mudar o quadro).

Mas também há casos em que têm getters e setters é um padrão bom. Um exemplo:

Quando eu criar o GUI de uma aplicação, eu tento manter o comportamento da GUI em uma classe (FooModel), de modo que ele pode ser unidade testada facilmente, e ter a visualização da GUI em outra classe (FooView) que pode ser testado apenas manualmente. A vista e modelo são unidas com cola código simples; quando o usuário altera o valor do x campo, a visão chama setX(String) do modelo, que por sua vez pode levantar um evento que alguma outra parte do modelo mudou, ea vista vai obter os valores atualizados do modelo com getters.

Em um projeto, há um modelo GUI que tem 15 getters e setters, dos quais apenas 3 métodos get são triviais (tal que o IDE pode gerá-los). Todos os outros contêm algumas funcionalidades ou não-triviais expressões, tais como o seguinte:

public boolean isEmployeeStatusEnabled() {
    return pinCodeValidation.equals(PinCodeValidation.VALID);
}

public EmployeeStatus getEmployeeStatus() {
    Employee employee;
    if (isEmployeeStatusEnabled()
            && (employee = getSelectedEmployee()) != null) {
        return employee.getStatus();
    }
    return null;
}

public void setEmployeeStatus(EmployeeStatus status) {
    getSelectedEmployee().changeStatusTo(status, getPinCode());
    fireComponentStateChanged();
}

Na prática Eu sempre sigo apenas uma regra, o "não size fits all" regra.

O encapsulamento e sua importância é um produto do seu projeto. O objeto será acessar sua interface, como eles vão usá-lo, irá importar se eles têm direitos de acesso desnecessários aos membros? essas perguntas e os gostos deles você precisa perguntar a si mesmo quando se trabalha em cada implementação do projeto.

Eu baseio a minha decisão sobre a profundidade do Código dentro de um módulo. Se eu estou escrevendo código que é interno a um módulo, e não interagir com o mundo exterior eu faço as coisas não encapsulam com a iniciativa privada, tanto porque afeta meu desempenho programador (o quão rápido eu posso escrever e reescrever o meu código).

Mas para os objetos que servidor como a interface do módulo com o código do usuário, então eu aderir aos padrões de privacidade rigorosa.

Com certeza ele faz a diferença se o seu código interno escrito ou código a ser usado por outra pessoa (ou mesmo por si mesmo, mas como uma unidade independente.) Qualquer código que vai ser usado externamente deve ter um bem definidos / documentado a interface que você vai querer mudar o mínimo possível.

Para código interno, dependendo da dificuldade, você pode achar que é menos trabalho para fazer as coisas da maneira simples agora, e pagar um pouco pena mais tarde. É claro que a lei de Murphy garantirá que o ganho de curto prazo será apagado muitas vezes em ter de fazer amplas mudanças depois de onde você precisava mudar uma classe internos que você não conseguiu encapsular.

Especificamente para o exemplo do uso de uma coleção que você voltaria, parece possível que a implementação de tal coleção pode mudar (ao contrário de variáveis ??de membro mais simples), tornando a utilidade de encapsulamento superior.

Dito isto, eu meio que gosto maneira de lidar com ele é Python. variáveis ??de membro são públicos por padrão. Se você quer escondê-los ou adicionar validação existem técnicas fornecidas, mas aqueles são considerados os casos especiais.

Eu sigo as regras sobre isso quase o tempo todo. Há quatro cenários para mim - basicamente, a própria regra e várias exceções (todos Java de influência):

  1. Pode ser usado por qualquer coisa fora da classe atual, acessada via getters / setters
  2. uso Interno-to-classe tipicamente precedido por 'isto' para deixar claro que não é um método parâmetro
  3. Algo significava ficar extremamente pequeno, como um objeto de transporte - basicamente um tiro certeiro de atributos; todos os públicos
  4. precisava ser não-privada para a extensão de algum tipo

Há uma preocupação prática aqui que não está sendo tratado pela maioria das respostas existentes. Encapsulamento e a exposição de interfaces seguras limpas para o código fora é sempre grande, mas é muito mais importante quando o código que você está escrevendo se destina a ser consumido por uma base de "usuário" spatially- e / ou temporalmente-large. O que quero dizer é que, se você está pensando em alguém (mesmo você) manter o código no futuro, ou se você estiver escrevendo um módulo que irá interagir com o código de mais de um punhado de outros desenvolvedores, você precisa pensar muito mais cuidado do que se você estiver escrevendo código que é ou one-off ou totalmente escrito por você.

Honestamente, eu sei o software infeliz prática de engenharia este é, mas vou muitas vezes tornar tudo público em primeiro lugar, o que torna as coisas ligeiramente mais rápido de lembrar e digitar, em seguida, adicione o encapsulamento, pois faz sentido. ferramentas de refatoração na maioria dos IDEs populares nos dias de hoje marcas que se aproximar de você usar (adicionando encapsulamento vs. tirá-la) muito menos relevante do que costumava ser.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top