Fiquei me perguntando se havia um caso de uso válido para poder definir corretamente as propriedades e funções internas específicas de uma classe de maneira semelhante à maneira como uma interface define as propriedades e funções públicas de uma classe.
Imagine a tarefa que você precisa para criar uma classe que descreva um ser humano.
Obviamente, cada humano é uma criatura humanóide, mas nem toda criatura humanóide é um humano, então você provavelmente teria uma interface IHumanoid com funções como estas (já que não é útil codificar o plano do corpo na classe):
public interface IHumanoid {
function get head():IHead;
function get torso():ITorso;
function get leftArm():IArm;
function get rightArm():IArm;
function get leftLeg():ILeg;
function get rightLeg():ILeg;
}
Além disso, e obviamente, cada humano é um mamífero, mas nem todo mamífero é um humano, então provavelmente há outra interface IMammal com duas definições para machos e fêmeas flutuando em algum lugar:
public interface IMammal {
function procreate(partner:IMammal):void;
}
public interface IMaleMammal extends IMammal {
function inseminate(female:IFemaleMammal):void;
}
public interface IFemaleMammal extends IMammal {
function conceive(partner:IMaleMammal):Boolean;
function giveBirth():IMammal;
function nurse(offspring:IMammal):void;
}
Portanto, nossa classe provavelmente se parece com isso agora:
public class Human implements IHumanoid, IMammal {
private var _head:IHead;
private var _torso:ITorso;
private var _leftArm:IArm;
private var _rightArm:IArm;
private var _leftLeg:ILeg;
private var _rightLeg:ILeg;
public function Human() {
// ctor...
}
public function get head():IHead {
return _head;
}
public function get torso():ITorso {
return _torso;
}
public function get leftArm():IArm {
return _leftArm;
}
public function get rightArm():IArm {
return _rightArm;
}
public function get leftLeg():ILeg {
return _leftLeg;
}
public function get rightLeg():ILeg {
return _rightLeg;
}
public function procreate(partner:IMammal):void {
// "abstract" function
}
}
public class MaleHuman extends Human implements IMaleMammal {
override public function procreate(partner:IMammal):void {
if (partner is IFemaleMammal) {
inseminate(partner);
}
}
public function inseminate(female:IFemaleMammal):void {
female.conceive(this);
}
}
public class FemaleHuman extends Human implements IFemaleMammal {
override public function procreate(partner:IMammal):void {
if (partner is IMaleMammal) {
conceive(partner);
}
}
public function conceive(partner:IMaleMammal):Boolean {
// ...
}
public function giveBirth():IMammal {
// ...
}
public function nurse(offspring:IMammal):void {
// ...
}
}
A partir disso, podemos implementar nossas classes ainda mais e tudo está funcionando bem até conseguirmos a tarefa de usar as interfaces existentes para implementar outras classes. Talvez um gorila, uma orca e um ornitorrinco.
Ignorando o enorme problema que o ornitorrinco colocará em nossa atual estrutura de interface (* tosse * mamífero que põe ovos * tosse *), temos o "problema" de que nada nos impede de dar ao cérebro do gorila 2, ao pulmão da orca 8 e à metade do ornitorrinco uma dúzia de fígados. E, embora possamos ser disciplinados o suficiente para seguir a estrutura que os mamíferos normalmente têm, não podemos garantir o mesmo se abrirmos a API para outros desenvolvedores que possam codificar algumas coisas seriamente erradas que ainda parecem boas para o mundo exterior.
Portanto, eu queria saber se havia um caso de uso válido para criar algo como uma "interface privada" que define funções e propriedades não públicas. Talvez algo nesse sentido:
public structure SMammal {
function get brain():IBrain;
function get liver():ILiver;
function get leftLung():ILung;
function get rightLung():ILung;
function get leftKidney():IKidney;
function get rightKidney():IKidney;
}
public class Human implements IHumanoid, IMammal follows SMammal {
private function get brain():IBrain {
// ...
}
private function get liver():ILiver {
// ...
}
// etc. etc.
}
Esse recurso existe em alguma linguagem de programação? Classes abstratas podem ser usadas para resolver isso? Ou não deveríamos nos preocupar com isso desde que a interface pública funcione de alguma forma como o esperado?
Respostas:
O que exatamente você ganha forçando-os a seguir sua estrutura? Você possivelmente quebra alguns usos avançados, talvez haja um caso para um animal com múltiplos cérebros. E o programador cliente pode atrapalhar a implementação de uma classe de tantas maneiras malucas que tentar impedir isso parece tentar fechar uma janela na tentativa de manter um cavalo em um celeiro.
Não trate seus programadores clientes como prisioneiros. Se eles seguirem a interface pública, deixe o código executar.
fonte
IList<T>
mas a interface exige que você retorne anIEnumerable<T>
). E por último, mas não menos importante, não há um animal conhecido com cérebros múltiplos (redundantes, como todos os nossos órgãos duplicados). Portanto, embora possa haver um argumento para algo assim (por exemplo, aranhas), quase certamente não será um mamífero, portanto seria uma interface / estrutura completamente diferente.Como um tipo de interface é por padrão um membro público, tudo dentro dele deve ser público, mas eu já vi isso:
/programming/792908/what-is-a-private-interface
de msdn:
http://msdn.microsoft.com/en-us/library/ms173156.aspx
fonte
Com certeza sim. Praticamente qualquer recurso existe em algum idioma.
Por exemplo, no Objective-C ++ (programação iOS / Mac), é um procedimento padrão para uma classe ter pelo menos duas interfaces. Em que é público, e que é privado. Às vezes, eles também têm interfaces extras definidas em outro local (por exemplo, a classe de string de baixo nível tem uma interface para executar operações de desenho de tela da GUI na string, que é definida em uma estrutura / biblioteca completamente separada daquela que define a string classe).
Basicamente, a maneira como trato público / privado é simples:
Os elementos da interface pública nunca podem ser alterados. Sempre que você refatorar ou melhorar seu código, a interface pública ainda precisará se comportar exatamente da mesma maneira que antes.
As interfaces privadas, por outro lado, podem ser alteradas ou completamente removidas sempre que você desejar. Contanto que você atualize todo o código da classe para entender o novo comportamento, você estará bem. Freqüentemente, a interface pública estará cheia de um ou dois métodos de linha que entregam o trabalho real à interface privada.
O Objective-C ++ também possui o conceito de "protegido" na interface, onde algo está disponível para subclasses, mas não para classes externas.
Normalmente, meu código é dividido entre meio público e privado. Eu não uso muito protegido, apesar de ser útil de vez em quando.
fonte
Pelo menos nas linguagens .NET, é possível aplicar um especificador de acesso a uma interface. Isso pode ser útil quando algumas combinações de classes internas de uma montagem compartilham habilidades comuns, mas essas combinações e habilidades não se encaixam em um relacionamento hierárquico. O fato de as habilidades não se ajustarem a um relacionamento hierárquico torna necessário o uso de interfaces para representá-las, mas de forma alguma implica que o código externo deva ter permissão para definir tipos que pretendem implementar as interfaces. Além disso, as interfaces não podem conter métodos cujos tipos de parâmetro ou retorno tenham acesso mais restrito do que as próprias interfaces. Se a classe
Fred
for declaradainternal
e uma interfaceIFred
tiver um método que retorne aFred
, a interface deverá ser declaradainternal
. Se a classe aninhadaFred.Joe
éprivate
e a interface aninhadaFred.IJoe
possui um método que retorna aFred.Joe
,Fred.IJoe
também deve ser declaradoprivate
.fonte