Me preguntaba si había un caso de uso válido para poder definir adecuadamente las propiedades y funciones internas específicas de una clase de manera similar a cómo una interfaz define las propiedades y funciones públicas de una clase.
Imagine la tarea que tiene que construir una clase que describe a un ser humano.
Obviamente, cada humano es una criatura humanoide, pero no todas las criaturas humanoides son humanas, por lo que probablemente tenga una interfaz IHumanoid con funciones como estas (ya que no es útil codificar el plan corporal en la clase):
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;
}
Además, y obviamente, cada humano es un mamífero, pero no todos los mamíferos son humanos, por lo que probablemente haya otra interfaz IMammal con dos definiciones para machos y hembras flotando en algún 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;
}
Por lo tanto, nuestra clase probablemente se parece a esto ahora:
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 de esto, podemos implementar nuestras clases aún más y todo funciona bien hasta que tengamos la tarea de usar las interfaces existentes para implementar algunas otras clases. Quizás un gorila, una orca y un ornitorrinco.
Ignorando el problema masivo que el ornitorrinco planteará a nuestra estructura de interfaz actual (* tos * mamífero pone huevos * tos *), tenemos el "problema" de que nada nos impide darle al gorila 2 cerebros, la orca 8 pulmones y el ornitorrinco medio una docena de hígados Y si bien podríamos ser lo suficientemente disciplinados para seguir la estructura que los mamíferos suelen tener, no podemos garantizar lo mismo si abrimos la API para otros desarrolladores que podrían codificar algunas cosas muy jodidas que aún se ven bien para el mundo exterior.
Por lo tanto, me preguntaba si había un caso de uso válido para crear algo así como una "interfaz privada" que define funciones y propiedades no públicas. Quizás algo en este 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.
}
¿Existe tal característica en algún lenguaje de programación? ¿Se pueden usar clases abstractas para resolver esto? ¿O no deberíamos preocuparnos por esto siempre que la interfaz pública funcione de alguna manera como se esperaba?