Por que precisamos de variáveis privadas?

202

Por que precisamos de variáveis privadas em classes?

Todo livro sobre programação que eu li diz que esta é uma variável privada, é assim que você define, mas para aí.

A formulação dessas explicações sempre me pareceu que realmente temos uma crise de confiança em nossa profissão. As explicações sempre soam como se outros programadores estivessem errados para estragar nosso código. No entanto, existem muitas linguagens de programação que não possuem variáveis privadas.

  1. O que as variáveis privadas ajudam a evitar?

  2. Como você decide se uma determinada propriedade deve ser privada ou não? Se, por padrão, cada campo DEVE ser privado, então por que membros de dados públicos em uma classe?

  3. Em que circunstâncias uma variável deve se tornar pública?

por mwallace 10.04.2012 / 07:31
fonte

14 respostas

295

Não é tanto uma questão de confiança, mas de gerenciamento de complexidade.

Um membro público pode ser acessado de fora da classe, o que, por considerações práticas, significa "potencialmente em qualquer lugar". Se algo der errado com um campo público, o culpado pode estar em qualquer lugar, e assim, a fim de rastrear o bug, você pode ter que olhar bastante código.

Um membro privado, por outro lado, só pode ser acessado de dentro da mesma classe, então se algo der errado com isso, geralmente há apenas um arquivo de origem para examinar. Se você tem um milhão de linhas de código em seu projeto, mas suas classes são pequenas, isso pode reduzir o esforço de rastreamento de bugs por um fator de 1000.

Outra vantagem está relacionada ao conceito de 'acoplamento'. Um membro público m de uma classe A que é usado por outra classe B apresenta uma dependência: se você alterar m em A , também deverá verificar os usos de m em B . Pior ainda, nada na classe A informa onde o m está sendo usado, então, novamente, você tem que pesquisar em toda a base de código; se é uma biblioteca que você está escrevendo, você precisa ter certeza de que o código fora do seu projeto não seja interrompido por causa da sua mudança. Na prática, as bibliotecas tendem a permanecer com suas assinaturas de métodos originais pelo maior tempo possível, não importa o quão dolorosas sejam, e então introduzem um bloco de alterações de quebra com uma grande atualização de versão. Com membros privados, por outro lado, você pode excluir dependências imediatamente - elas não podem ser acessadas de fora, então todas as dependências estão contidas dentro da classe.

Nesse contexto, "outros programadores" incluem seus eus futuros e anteriores. É provável que você saiba agora que você não deve fazer essa coisa X com sua variável Y, mas você deve ter esquecido de três meses quando um cliente precisa urgentemente de você para implementar algum recurso, e você se pergunta por que fazer X quebra Y de maneira obscura.

Então, quando você deve tornar as coisas privadas: eu diria que torne tudo privado por padrão e exponha apenas as partes que precisam ser públicas. Quanto mais você puder tornar privado, melhor.

    
por 10.04.2012 / 07:48
fonte
110

As variáveis privadas ajudam a impedir que as pessoas dependam de certas partes do seu código. Por exemplo, digamos que você queira implementar alguma estrutura de dados. Você quer que os usuários da sua estrutura de dados não se importem com o modo como você a implementou, mas apenas usar a implementação através de sua interface bem definida. O motivo é que, se ninguém depende da sua implementação, você pode alterá-la sempre que quiser. Por exemplo, você pode alterar a implementação de back-end para melhorar o desempenho. Quaisquer outros desenvolvedores que dependam de suas implementações serão interrompidos, enquanto os usuários da interface estarão bem. Ter a flexibilidade de alterar implementações sem afetar os usuários da turma é um grande benefício que o uso de variáveis privadas (e mais amplamente, encapsulamento ) oferece a você.

Além disso, não é realmente uma "crise de confiança". Se você tornar público um dado, não poderá garantir que ninguém dependa dele. Geralmente, é muito conveniente depender de alguma variável específica da implementação, em vez de passar pela interface pública, especialmente no calor de um prazo. Além disso, os desenvolvedores nem sempre percebem que estão dependendo de algo que possa mudar.

Então este tipo de respostas para suas outras perguntas, eu espero. Todos os detalhes da sua implementação devem ser privados, e a parte pública deve ser uma interface pequena, concisa e bem definida para usar sua classe.

    
por 10.04.2012 / 07:41
fonte
24

A palavra-chave aqui é Encapsulation . Em OOP você deseja usar variáveis privadas para impor o encapsulamento apropriado de seus objetos / classes.

Enquanto outros programadores não estão à sua disposição, eles interagem com o seu código. Se você não tornar uma variável privada, ela poderá se referir a ela em seu próprio código sem querer causar nenhum dano. No entanto, se você precisar voltar à sua aula e mudar alguma coisa, não saberá mais quem usa qual variável e onde. O objetivo do encapsulamento é tornar explícita a interface externa da classe, para que você saiba que somente esses (normalmente) métodos poderiam ter sido usados por outras pessoas.

  1. Portanto, as variáveis privadas garantem que a variável correspondente permaneça apenas na classe de definição. Se você precisar alterá-lo, a mudança é local para a própria classe.

  2. Em linguagens tradicionais como C ++ ou Java, você geralmente torna tudo privado e acessível somente por getters e setters correspondentes. Não há necessidade de decidir muito.

  3. Às vezes, f.ex. em uma estrutura C ++, você precisa de uma classe apenas para agrupar várias coisas. Por exemplo, considere uma classe Vector que tenha apenas um atributo x e y . Nesses casos, você pode permitir acesso direto a esses atributos, declarando-os públicos. Em particular, você não deve se importar se algum código externo modificar um objeto da sua classe escrevendo diretamente novos valores em x ou y .

Como um ponto adicional, observe que esse assunto é considerado um pouco diferente em outros idiomas. Por exemplo, linguagens strongmente enraizadas na programação funcional enfatizam a imutabilidade dos dados, ou seja, os valores de dados não podem ser alterados. Nesses casos, você não precisa se importar com o que os outros programadores (ou melhor, o código deles) fazem com seus dados. Eles simplesmente não podem fazer nada que possa afetar seu código, porque todos os dados são imutáveis.

Nesses idiomas, você recebe algo chamado princípio de acesso uniforme , em que deliberadamente não se distingue métodos como getters e getters. setters, mas fornece acesso direto à variável / função. Então você pode dizer que as declarações privadas são muito mais populares nos cenários orientados a objetos.

Isso também mostra como ampliar seus conhecimentos para incluir outros campos faz com que você visualize os conceitos existentes de uma maneira totalmente nova.

    
por 10.04.2012 / 07:48
fonte
6

As variáveis privadas garantem que referências posteriores fora do escopo de um objeto ou função não afetem inadvertidamente outras variáveis. Para grandes projetos de programação, isso pode ajudar a evitar muitos problemas interessantes (que geralmente não são capturados pelo compilador).

Por exemplo, linguagens prototípicas, como o Javascript, podem permitir que os usuários coloquem em gesso as variáveis que entenderem:

function SomeObject() {
    this.a = 2; //Public (well, actually protected) variable

    this.showA = function() {
        alert(this.a);
    }
}

//Some lines down...

var obj = new SomeObject();
obj.a = 3;
obj.showA(); //Will alert 3. Uh oh!

Se essa variável fosse privada, não seria possível alterá-la de fora:

function SomeObject() {
    var a = 2; //Private variable

    this.showA = function() {
        alert(a);
    }
}

//Some lines down...

var obj = new SomeObject();
obj.a = 3;
obj.showA(); //Will alert 2

Dito isso, nem todas as variáveis precisam ser privadas e o uso excessivo de variáveis privadas pode realmente tornar o código mais complicado. Campos triviais que não afetam seriamente um objeto não precisam dos métodos get() e set() .

Variáveis privadas também facilitam a expansão de código no futuro, sem depender de documentação pesada sobre o que as muitas variáveis públicas fazem. Há menos ameaça de quebra acidental da funcionalidade se menos variáveis puderem ser sobrescritas.

Variáveis públicas devem ser usadas quando um objeto / função estiver acessando outros objetos / funções, já que, via de regra, variáveis privadas não podem fazer isso. Você pode ter desde algumas até algumas variáveis públicas, e não é uma coisa ruim usá-las se elas forem usadas corretamente.

    
por 10.04.2012 / 07:52
fonte
6

Existem algumas boas respostas citando os benefícios para futuros mantenedores e usuários de uma classe. No entanto, também há benefícios para o design original. Ele fornece um ponto de demarcação claro entre quando seu objetivo é facilitar as coisas para você mesmo e quando seu objetivo é facilitar as coisas para o usuário da turma. Quando você escolhe entre público e privado, sinaliza para o seu cérebro mudar para um modo ou outro, e você acaba com uma API melhor.

Não é que idiomas sem privacidade tornem esse design impossível, apenas menos provável. Em vez de ser solicitado a escrever algo como foo.getBar() , as pessoas tendem a pensar que um getter não é necessário, porque é mais fácil escrever foo.bar , mas essa decisão não é revisitada quando você acaba com monstruosidades mais longas como %código%. Programadores que nunca trabalharam em uma linguagem mais estrita podem nem ver o que há de errado com isso.

É por isso que, em idiomas sem privacidade, as pessoas geralmente adotam padrões de nomenclatura que simulam esses padrões, como a inclusão de um sublinhado em todos os membros "privados". É um sinal útil mesmo quando a linguagem não o impõe.

    
por 10.04.2012 / 17:53
fonte
3

Todas as variáveis devem ser privadas, a menos que elas absolutamente precisem ser públicas (o que é quase nunca, você deve usar propriedades / getters e setters).

As variáveis fornecem o estado do objeto e as variáveis privadas impedem que outras pessoas entrem e alterem o estado do objeto.

    
por 10.04.2012 / 07:38
fonte
2
  • O que as variáveis privadas ajudam a evitar?

Trata-se de deixar claro quais propriedades e métodos são a interface e quais são, na verdade, a principal funcionalidade. Métodos / propriedades públicos são sobre outro código, muitas vezes código de outro desenvolvedor usando seus objetos. Eu nunca trabalhei em equipes de 100+ no mesmo projeto, mas na minha experiência de talvez equipes de 3-5 com até 20 outros desenvolvedores usando coisas que eu escrevi, as outras preocupações parecem tolas.

Nota: Sou principalmente um desenvolvedor de JavaScript. Eu geralmente não me preocupo com outros desenvolvedores que visualizam meu código, e opero com plena consciência de que eles poderiam simplesmente redefinir minhas coisas a qualquer momento. Eu suponho que eles são competentes o suficiente para saber o que estão fazendo primeiro. Caso contrário, é improvável que eu esteja trabalhando em uma equipe que não use controle de origem.

  • Como você decide se um determinado conjunto de propriedades deve ser privado ou não? Se, por padrão, cada campo DEVE ser privado, por que há membros de dados públicos em uma classe?

Eu costumava pensar que era bobagem colocar getters e setters em propriedades privadas quando você não estava realmente realizando nenhum tipo de validação ou outro tratamento especial da propriedade a ser definida. Eu ainda não acho que é sempre necessário, mas quando você está lidando com grande escala, alta complexidade, mas o mais importante é que muitos outros desenvolvedores confiam em seus objetos se comportando de maneira consistente, pode ser útil fazer coisas em um maneira consistente e uniforme. Quando as pessoas veem métodos chamados getThat e setThat , eles sabem exatamente quais são as intenções e podem escrever seus objetos para interagir com os seus com a expectativa de que sempre obterão tomates em vez de tomahtos. Se não, eles sabem que seu objeto está dando a eles algo que provavelmente não deveria, o que significa que está permitindo que algum outro objeto faça algo com os dados que provavelmente não deveria. Você pode controlar isso conforme a necessidade.

A outra grande vantagem é que é mais fácil ter seus objetos entregues ou interpretar valores de forma diferente de um getter ou setter com base em algum tipo de contexto de estado variável. Como estão acessando suas coisas com um método, é muito mais fácil alterar a maneira como seu objeto opera posteriormente, sem violar outro código que dependa dele. O princípio importante é que apenas o seu objeto realmente altera os dados pelos quais você é responsável. Isso é particularmente importante para manter seu código fracamente acoplado, o que é uma grande vitória em termos de portabilidade e facilidade de modificação.

  • Em que circunstâncias uma variável deve ser tornada pública?

Com funções de primeira classe (você pode passar funções como argumentos), não consigo pensar em muitas outras razões além de não ser extremamente necessário fazê-lo em projetos de menor escala. Sem isso, eu suponho que você pode ter membros que estão sendo processados pesadamente e regularmente por outros objetos na medida em que parece um pouco difícil de chamar constantemente get e define um objeto que realmente não toca os dados em si, mas que em em si me faria pensar por que o objeto era responsável por esses dados. De um modo geral, eu tenderia a querer reexaminar minha arquitetura quanto a falhas antes de decidir se uma propriedade de dados pública é necessária. IMO, não há nada de errado com uma linguagem que permite fazer algo que geralmente é uma má ideia. Algumas linguagens discordam.

    
por 10.04.2012 / 18:47
fonte
2

Veja esta postagem minha para uma pergunta relacionada sobre SO .

O mais curto é que o escopo variável permite que você mostre aos consumidores do seu código com o que eles deveriam ou não estar brincando. Uma variável privada pode conter dados que foram "verificados" usando um setter de propriedade ou um método de processamento para garantir que o objeto inteiro esteja em estado consistente. Alterar diretamente o valor da variável privada pode fazer com que o objeto se torne inconsistente. Ao torná-lo privado, alguém precisa trabalhar muito e ter permissões de tempo de execução realmente altas para alterá-lo.

O escopo adequado dos membros é, portanto, fundamental no código de autodocumentação.

    
por 10.04.2012 / 16:42
fonte
2

Não tem nada a ver com confiança ou medo de ataques, é apenas sobre encapsulamento - não forçar informações desnecessárias sobre o usuário da classe.

Considere as constantes privadas - elas não devem conter valores secretos (elas devem ser armazenadas em outro lugar), elas não podem ser alteradas, elas não precisam ser passadas para sua classe (caso contrário, elas teriam que ser públicas). O único uso possível para eles é como constantes em outras classes. Mas se você fizer isso, essas classes dependerão da sua turma para fazer um trabalho que não esteja relacionado à sua turma. Se você alterar a constante, outras classes poderão quebrar. Isso é ruim de ambos os lados - como o escritor de sua classe, você quer a liberdade de mudar o máximo possível, e não quer se preocupar com coisas fora do seu controle. Um consumidor da sua turma quer ser capaz de depender dos detalhes expostos da sua turma, sem se preocupar em alterá-lo e violar o código deles.

Um consumidor da sua classe quer saber tudo o que é necessário para o INTERACT com a sua turma e não quer saber nada sobre a sua turma que não altere a forma como o fazem: trata-se de trivialidades inúteis. Se você usou um langauge com reflexão, com que frequência você o usou para aprender não como alguma classe faz algo ou onde está lançando uma exceção inesperadamente, mas simplesmente o nome dos campos e métodos privados? Eu estou apostando nunca. Porque você não tem utilidade para esse conhecimento.

    
por 10.04.2012 / 17:41
fonte
1

O conceito OOP possui herança possui um de seus recursos (Java ou C ++). Então, se vamos herdar (ou seja, vamos acessar as variáveis da classe herdada), existe a possibilidade de afetar essas variáveis. Então temos que decidir se as variáveis podem ser alteradas ou não.

Apenas para este propósito, estamos usando modificadores de acesso em OOP. Um dos modificadores é privado, o que significa que só pode ser acessado por essa classe. Qualquer outra classe não pode afetar essas variáveis.

Como sabemos, protegido significa que ele pode ser acessado pela classe que herdará.

Por que há um conceito de modificador em OOP, é devido a essas razões (qualquer classe pode acessar outras variáveis de classe usando o conceito OOP). Se não houver um conceito de modificador, isso significa que seria difícil herdar classes ou usar outros conceitos de OOP.

    
por 10.04.2012 / 07:52
fonte
1

Eu vou falar sobre o valor do encapsulamento de uma perspectiva diferente usando um exemplo real. Muito tempo atrás (início dos anos 80) um jogo foi escrito para o Radio Shack Color Computer chamado Dungeons of Daggorath. Alguns anos atrás, Richard Hunerlach o portou de uma lista de montadores de papel para C / C ++ ( link ). Algum tempo depois, peguei o código e comecei a refazê-lo para dar melhor encapsulamento, ( link ).

O código já foi fatorado em diferentes objetos para manipular o agendamento, o vídeo, a entrada do usuário, a criação de masmorras, os monstros, etc., mas você definitivamente poderia dizer que ele foi portado do assembler. Minha maior tarefa foi aumentar o encapsulamento. Com isso, pretendo obter diferentes partes do código para tirar o nariz dos negócios uns dos outros. Havia muitos lugares, por exemplo, que mudariam as variáveis de vídeo diretamente para ter algum efeito. Alguns fizeram isso com a verificação de erros, outros não, alguns tinham idéias sutilmente diferentes sobre o que mudaria essa coisa. Houve muita duplicação de código. Em vez disso, a seção de vídeo precisava ter uma interface para realizar as tarefas desejadas, e o código para fazer isso poderia estar em um só lugar, em uma ideia, em um lugar para depurar. Esse tipo de coisa era galopante. Todo objeto acessado diretamente a todos os outros objetos e códigos foi duplicado em todos os lugares.

Quando o código começou a ser desmembrado, bugs que não tinham sido diagnosticados desapareceram. O código se tornou de maior qualidade. Cada tarefa tornou-se responsabilidade de um lugar no código e havia apenas um lugar para acertar. (Eu ainda acho mais cada vez que faço outra passagem pelo código.)

Tudo o que é visível sobre o seu código é sua interface. Quer você queira ou não. Se você limitar a visibilidade, tanto quanto possível, então você não será tentado a colocar o código no lugar errado mais tarde. Torna óbvio que parte do código é responsável por quais dados. Faz um design melhor, mais limpo, mais simples e elegante.

Se você tornar um objeto responsável por seus próprios dados e fornecer interfaces para todos os outros que precisam que algo aconteça, seu código ficará muito mais simples. Apenas cai fora. Você tem pequenas rotinas simples que fazem apenas uma coisa. Menos complexidade == menos bugs.

    
por 17.04.2012 / 21:27
fonte
1

Como afirmam outros, as variáveis privadas são boas para evitar erros de uso levando o objeto a um status inconsistente e difíceis de rastrear bugs e exceções imprevistas.

Mas, por outro lado, o que tem sido ignorado pelos outros é sobre campos protegidos.

Uma subclasse estendida terá acesso total aos campos protegidos, tornando o objeto tão frágil como se esses campos fossem públicos, mas essa fragilidade é limitada à própria classe de extensão (a menos que expusesse esses campos ainda mais).

Assim, campos públicos são difíceis de serem considerados bons, e até a data a única razão para usá-los é para classes usadas como parâmetros de configuração (uma classe muito simples com muitos campos e nenhuma lógica, então essa classe é passada como um parâmetro sozinho para algum método).

Mas, por outro lado, os campos privados reduzem a flexibilidade do seu código para outros usuários.

Flexibilidade versus problemas, prós e contras:

Objetos instanciados pelo seu código na classe baunilha com campos protegidos são seguros e são de sua inteira responsabilidade.

Por outro lado, os objetos que estendem sua classe com campos protegidos, instanciados pelos usuários do seu código, são de sua responsabilidade, não da sua.

Portanto, campos / métodos protegidos não documentados, ou se os usuários realmente não entenderem como esses campos e métodos devem ser usados, têm uma boa chance de causar problemas desnecessários a si mesmos e a você.

Por outro lado, tornar a maioria das coisas privadas diminuirá a flexibilidade dos usuários e poderá até mesmo colocá-los à procura de alternativas mantidas, já que talvez não queiram criar e manter um fork apenas para que as coisas aconteçam.

Assim, um bom equilíbrio entre privado, protegido e público é o que realmente importa.

Agora, decidir entre privado e protegido é o verdadeiro problema.

Quando usar protegido?

Toda vez que você entende que um campo pode ser altamente flexível, ele deve ser codificado como protegido. Essa flexibilidade é: de tornar-se nula (onde nulo é sempre verificado e reconhecido como um estado válido não lançando exceções), para ter restrições antes de ser usado por sua classe ex. > = 0, < 100, etc, e automaticamente corrigidos para valores acima / abaixo do fluxo, jogando no máximo uma mensagem de aviso.

Assim, para esse campo protegido, você pode criar um getter e usá-lo (em vez de usar diretamente a variável field), enquanto outros usuários podem não usá-lo, caso desejem mais flexibilidade para seu código específico, no meu exemplo poderia ser como: se eles querem valores negativos para funcionar bem em sua classe estendida.

    
por 17.06.2016 / 04:48
fonte
0

imo @tdammers não está certo e é realmente enganador.

Variáveis privadas existem para ocultar detalhes da implementação. Sua classe A pode estar usando array para armazenar as pontuações. Amanhã você pode querer usar um tree ou priority queue . Todos os usuários da sua turma precisam de uma maneira de inserir pontuações e nomes addScore() e uma maneira de descobrir quem são os 10% melhoresgetTop(n).

Eles não precisam acessar a estrutura de dados subjacente. Parece bom? Bem, existem algumas ressalvas.

Você não deve armazenar muito estado, a maioria não é necessária. O estado de armazenamento complicará seu código mesmo quando for "segregado" para uma classe específica. Pense nisso, essa variável privada provavelmente mudou porque outro objeto chamou um método dessa classe. Você ainda precisa descobrir quando e onde esse método foi chamado e esse método público pode ser chamado em qualquer lugar teoricamente.

A melhor coisa que você pode fazer é limitar a quantidade de estado que o seu programa contém e usar funções puras quando possível.

    
por 03.05.2017 / 20:05
fonte
-4

Você deve primeiro entender o conceito de programação orientada a objetos. Tem abstração, encapsulamento etc.

Abstração - Você tem a ideia da lógica sem precisar saber detalhes de sublinhado da implementação.

Encapsulamento - Você não pode ver a implementação de sublinhado do objeto. Só você pode ver a interface pública do objeto.

Agora, na implementação específica com um dos programas orientados a objetos, como C #, Java, C ++, você pode implementar esses conceitos.

private - A implementação que deve ser escondida do mundo exterior. Para que você possa mudar isso e o usuário da sua turma não seja afetado.

public - Essa é a interface pela qual você pode usar seu objeto.

    
por 27.06.2013 / 15:08
fonte