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?
Respuestas:
¿Qué ganas exactamente al obligarlos a seguir tu estructura? Posiblemente rompa algunos usos avanzados, tal vez haya un caso para un animal con múltiples cerebros. Y el programador del cliente puede estropear la implementación de una clase de tantas maneras locas que tratar de evitar esto se siente como tratar de cerrar una ventana en un intento de mantener un caballo en un establo.
No trate a sus programadores clientes como prisioneros. Si siguen la interfaz pública, deje que se ejecute el código.
fuente
IList<T>
pero la interfaz exige que regrese anIEnumerable<T>
) Y por último, pero no menos importante, hay un afaik animal no conocido con múltiples cerebros (redundantes, como todos nuestros órganos duplicados). Entonces, aunque puede haber un caso para algo como esto (por ejemplo, arañas), casi con certeza no será un mamífero, por lo que sería una interfaz / estructura completamente diferente de todos modos.Como un tipo de interfaz es por defecto un miembro público, todo lo que contiene debe ser público, pero he visto esto:
/programming/792908/what-is-a-private-interface
de msdn:
http://msdn.microsoft.com/en-us/library/ms173156.aspx
fuente
Seguro que sí. Prácticamente cualquier característica existe en algún idioma.
Por ejemplo, en Objective-C ++ (programación iOS / Mac) es un procedimiento estándar para que una clase tenga al menos dos interfaces. En eso es público, y uno que es privado. A veces también tendrán interfaces adicionales que se definen en otro lugar (por ejemplo, la clase de cadena de bajo nivel tiene una interfaz para realizar operaciones de dibujo de pantalla GUI en la cadena, que se define en un marco / biblioteca completamente separado del que define la cadena clase).
Básicamente, la forma en que trato público / privado es simple:
Los elementos de la interfaz pública nunca se pueden cambiar. Cada vez que refactoriza o mejora su código, la interfaz pública aún debe comportarse exactamente igual que antes.
Las interfaces privadas, por otro lado, se pueden cambiar o eliminar por completo cuando lo desee. Siempre y cuando actualice todo el código de la clase para comprender el nuevo comportamiento, está bien. A menudo, la interfaz pública estará llena de métodos de una o dos líneas que entregan el trabajo real a la interfaz privada.
Objective-C ++ también tiene el concepto de "protegido" en la interfaz, donde hay algo disponible para las subclases pero no para las clases externas.
Por lo general, mi código se divide aproximadamente a la mitad entre público y privado. No uso mucho protegido, aunque es útil de vez en cuando.
fuente
Al menos en los lenguajes .NET, es posible aplicar un especificador de acceso a una interfaz. Esto puede ser útil cuando algunas combinaciones de las clases internas de una asamblea comparten habilidades comunes, pero esas combinaciones y habilidades no se ajustan a una relación jerárquica. El hecho de que las habilidades no se ajusten a una relación jerárquica hace que sea necesario usar interfaces para representarlas, pero de ninguna manera implica que se debe permitir que el código externo defina tipos que afirman implementar las interfaces. Además, las interfaces no pueden contener ningún método cuyos tipos de parámetros o tipos de retorno tengan un acceso más estrecho que las interfaces mismas. Si
Fred
se declara la claseinternal
y una interfazIFred
tiene un método que devuelve aFred
, entonces la interfaz debe declararseinternal
. Si la clase anidadaFred.Joe
esprivate
y la interfaz anidadaFred.IJoe
tiene un método que devuelve aFred.Joe
,Fred.IJoe
también debe declararseprivate
.fuente