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?