Você deve usar variáveis de membro protegidas? Quais são as vantagens e quais problemas isso pode causar?
Você deve usar variáveis de membro protegidas? Quais são as vantagens e quais problemas isso pode causar?
Respostas:
Você deve usar variáveis de membro protegidas?
Depende de quão exigente você é sobre esconder o estado.
Se um desenvolvedor vier e criar uma subclasse de sua classe, ele pode bagunçar tudo porque não a entende completamente. Com membros privados, exceto a interface pública, eles não podem ver os detalhes específicos de implementação de como as coisas estão sendo feitas, o que lhe dá a flexibilidade de alterá-lo posteriormente.
O sentimento geral hoje em dia é que eles causam acoplamento indevido entre classes derivadas e suas bases.
Eles não têm nenhuma vantagem particular sobre métodos / propriedades protegidos (uma vez eles podem ter uma ligeira vantagem de desempenho), e eles também foram mais usados em uma época em que herança muito profunda estava na moda, o que não é no momento.
no particular advantage over protected methods/properties
ser no particular advantage over *private* methods/properties
?
super
construção para chamar o construtor pai; ele então se encarregará de inicializar variáveis de estado privado na classe pai.
Geralmente, se algo não é deliberadamente concebido como público, eu o torno privado.
Se surgir uma situação em que preciso acessar essa variável privada ou método de uma classe derivada, eu altero de privado para protegido.
Isso quase nunca acontece - eu realmente não sou um fã de herança, já que não é uma maneira particularmente boa de modelar a maioria das situações. De qualquer forma, continue, sem problemas.
Eu diria que isso é bom (e provavelmente a melhor maneira de fazer isso) para a maioria dos desenvolvedores.
O simples fato da questão é que , se algum outro desenvolvedor aparecer um ano depois e decidir que precisa de acesso à sua variável de membro privada, ele simplesmente editará o código, mudará para protegido e continuará com seus negócios.
As únicas exceções reais a isso são se você está no negócio de remessa de DLLs binárias na forma de caixa preta para terceiros. Isso consiste basicamente na Microsoft, aqueles fornecedores de 'Controle de DataGrid personalizado' e talvez alguns outros aplicativos grandes que vêm com bibliotecas de extensibilidade. A menos que você esteja nessa categoria, não vale a pena gastar tempo / esforço para se preocupar com esse tipo de coisa.
O problema principal para mim é que, depois de tornar uma variável protegida, você não pode permitir que nenhum método em sua classe dependa de seu valor estar dentro de um intervalo, porque uma subclasse sempre pode colocá-lo fora do intervalo.
Por exemplo, se eu tenho uma classe que define a largura e a altura de um objeto renderizável e faço essas variáveis protegidas, não posso fazer suposições sobre (por exemplo), a proporção de aspecto.
Criticamente, nunca posso fazer essas suposições em qualquer ponto a partir do momento em que o código é lançado como uma biblioteca, pois mesmo que eu atualize meus setters para manter a proporção de aspecto, não tenho garantia de que as variáveis estão sendo definidas por meio dos setters ou acessadas por meio do getters no código existente.
Nenhuma subclasse de minha classe pode optar por fazer essa garantia, pois eles também não podem impor os valores das variáveis, mesmo que esse seja o ponto inteiro de sua subclasse .
Como um exemplo:
Ao restringir as variáveis para que sejam privadas, posso então impor o comportamento que desejo por meio de setters ou getters.
Em geral, eu manteria suas variáveis de membro protegidas para o caso raro em que você tenha controle total sobre o código que as usa também. Se você estiver criando uma API pública, eu diria que nunca. A seguir, vamos nos referir à variável de membro como uma "propriedade" do objeto.
Aqui está o que sua superclasse não pode fazer depois de tornar uma variável de membro protegida em vez de privada com acessadores:
Preguiçosamente crie um valor na hora quando a propriedade está sendo lida. Se você adicionar um método getter protegido, poderá criar preguiçosamente o valor e passá-lo de volta.
saber quando a propriedade foi modificada ou excluída. Isso pode introduzir bugs quando a superclasse faz suposições sobre o estado dessa variável. Fazer um método setter protegido para a variável mantém esse controle.
Defina um ponto de interrupção ou adicione saída de depuração quando a variável for lida ou gravada.
Renomeie essa variável de membro sem pesquisar em todo o código que pode usá-la.
Em geral, acho que seria raro eu recomendar fazer uma variável de membro protegida. É melhor você gastar alguns minutos expondo a propriedade por meio de getters / setters do que horas depois rastreando um bug em algum outro código que modificou a variável protegida. Além disso, você está seguro contra a adição de funcionalidades futuras (como carregamento lento) sem quebrar o código dependente. É mais difícil fazer isso depois do que agora.
No nível de design, pode ser apropriado usar uma propriedade protegida, mas para implementação não vejo nenhuma vantagem em mapear isso para uma variável de membro protegida em vez de métodos acessadores / modificadores.
As variáveis de membro protegido têm desvantagens significativas porque permitem efetivamente o acesso do código do cliente (a subclasse) ao estado interno da classe base. Isso evita que a classe base mantenha efetivamente suas invariantes.
Pelo mesmo motivo, as variáveis de membro protegidas também tornam a gravação de código multithread seguro significativamente mais difícil, a menos que seja constante garantida ou confinada a uma única thread.
Os métodos de acesso / mutador oferecem consideravelmente mais estabilidade de API e flexibilidade de implementação sob manutenção.
Além disso, se você for um purista OO, os objetos colaboram / se comunicam enviando mensagens, não lendo / definindo o estado.
Em troca, oferecem poucas vantagens. Eu não os removeria necessariamente do código de outra pessoa, mas não os uso pessoalmente.
Na maioria das vezes, é perigoso usar protected porque você quebra um pouco o encapsulamento de sua classe, que poderia muito bem ser dividida por uma classe derivada mal projetada.
Mas eu tenho um bom exemplo: digamos que você possa algum tipo de recipiente genérico. Possui uma implementação interna e acessores internos. Mas você precisa oferecer pelo menos 3 acesso público aos seus dados: map, hash_map, vector-like. Então você tem algo como:
template <typename T, typename TContainer>
class Base
{
// etc.
protected
TContainer container ;
}
template <typename Key, typename T>
class DerivedMap : public Base<T, std::map<Key, T> > { /* etc. */ }
template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }
template <typename T>
class DerivedVector : public Base<T, std::vector<T> > { /* etc. */ }
Usei esse tipo de código há menos de um mês (portanto, o código vem da memória). Depois de pensar um pouco, acredito que embora o container Base genérico deva ser uma classe abstrata, mesmo que possa viver muito bem, porque usar o Base diretamente seria uma dor, deveria ser proibido.
Resumo Assim, você protegeu os dados usados pela classe derivada. Ainda assim, devemos levar em consideração o fato de que a classe Base deve ser abstrata.
protected
não é mais encapsulado do que public
. Estou disposto a provar que estou errado. Tudo que você tem a fazer é escrever uma classe com um membro protegido e me proibir de modificá-lo. Obviamente, a classe não pode ser final, já que o objetivo de usar protected é para herança. Ou algo está encapsulado ou não. Não existe um estado intermediário.
Resumindo, sim.
As variáveis de membro protegidas permitem o acesso à variável de qualquer subclasse, bem como de qualquer classe no mesmo pacote. Isso pode ser muito útil, especialmente para dados somente leitura. Não acredito que eles sejam necessários, no entanto, porque qualquer uso de uma variável de membro protegida pode ser replicado usando uma variável de membro privada e alguns getters e setters.
Para informações detalhadas sobre modificadores de acesso .Net, clique aqui
Não há vantagens ou desvantagens reais nas variáveis de membro protegidas, é uma questão de o que você precisa em sua situação específica. Em geral, é uma prática aceita declarar variáveis de membro como privadas e permitir o acesso externo por meio de propriedades. Além disso, algumas ferramentas (por exemplo, alguns mapeadores O / R) esperam que os dados do objeto sejam representados por propriedades e não reconhecem variáveis de membro públicas ou protegidas. Mas se você sabe que deseja que suas subclasses (e SOMENTE suas subclasses) acessem uma determinada variável, não há razão para não declará-la como protegida.