I was wondering if there was a valid use case for being able to properly define the specific internal properties and functions of a class in a way similar to how an interface defines the public properties and functions of a class.
Imagine the task that you have to build a class that describes a human being.
Obviously, each human is a humanoid creature but not every humanoid creature is a human so you'd probably have an interface IHumanoid with functions like these (since it isn't useful to hardcode the body plan into the class):
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;
}
Further and also obviously, each human is a mammal but not every mammal is a human, so there's probably another interface IMammal with two definitions for males and females floating around somewhere:
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;
}
Thus our class probably looks something like this now:
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 {
// ...
}
}
From this we can implement our classes further and everything's working nice and fine until we get the task to use the existing interfaces to implement some other classes. Perhaps a gorilla, an orca and a platypus.
Ignoring the massive issue the platypus will pose to our current interface structure (*cough* egg laying mammal *cough*), we have the "problem" that nothing prevents us from giving the gorilla 2 brains, the orca 8 lungs and the platypus half a dozen livers. And while we might be disciplined enough to follow the structure mammals typically have we cannot guarantee the same if we open the API for other developers who might code some seriously screwed up things which still look okay to the outside world.
Therefore I was wondering if there was a valid use case to create something like a "private interface" which defines non-public functions and properties. Perhaps something along these lines:
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.
}
Does such a feature exist in any programming language? Can abstract classes be used to solve this? Or shouldn't we care about this at all as long as the public interface somehow works as expected?