Mi chiedevo se esistesse un caso d'uso valido per essere in grado di definire correttamente le proprietà e le funzioni interne specifiche di una classe in modo simile a come un'interfaccia definisce le proprietà e le funzioni pubbliche di una classe.
Immagina l'attività che devi costruire per una classe che descrive un essere umano.
Ovviamente, ogni umano è una creatura umanoide, ma non tutte le creature umanoidi sono umane quindi probabilmente avresti un'interfaccia IHumanoide con funzioni come queste (dato che non è utile inserire il codice del corpo nella 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;
}
Inoltre, e ovviamente, ogni essere umano è un mammifero ma non tutti i mammiferi sono umani, quindi probabilmente c'è un'altra interfaccia IMammal con due definizioni per maschi e femmine che fluttuano da qualche parte:
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;
}
Quindi la nostra classe probabilmente assomiglia a qualcosa del genere ora:
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 {
// ...
}
}
Da questo possiamo implementare ulteriormente le nostre classi e tutto funziona bene fino a quando non avremo il compito di utilizzare le interfacce esistenti per implementare altre classi. Forse un gorilla, un'orca e un ornitorinco.
Ignorando l'enorme problema che l'ornitorinco porrà alla nostra attuale struttura dell'interfaccia (* cough * uovo che posa mammifero * tosse *), abbiamo il "problema" che nulla ci impedisce di dare il cervello del gorilla 2, l'orca 8 polmoni e il platypus mezza dozzina di fegati. E mentre noi potremmo essere abbastanza disciplinati da seguire la struttura, i mammiferi in genere non possono garantire lo stesso se apriamo l'API per altri sviluppatori che potrebbero codificare alcune cose seriamente incasinate che sembrano ancora valide per il mondo esterno.
Quindi mi chiedevo se esistesse un caso d'uso valido per creare qualcosa come una "interfaccia privata" che definisce funzioni e proprietà non pubbliche. Forse qualcosa in questo senso:
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.
}
Questa caratteristica esiste in qualsiasi linguaggio di programmazione? Le classi astratte possono essere utilizzate per risolvere questo? O non dovremmo preoccuparci di questo a patto che l'interfaccia pubblica funzioni in qualche modo come previsto?