2010-05-29 15 views
12

Ya hay varios SO preguntas sobre por qué no hay método/campo estático abstracta como tal, pero me pregunto acerca de cómo se podría ir sobre la aplicación de la siguiente pseudo-código:Método "Resumen estático": ¿cómo?

class Animal { 
    abstract static int getNumberOfLegs(); // not possible 
} 

class Chicken inherits Animal { 
    static int getNumberOfLegs() { return 2; } 


class Dog inherits Animal { 
    static int getNumberOfLegs() { return 4; } 

Aquí es el problema : Asumiendo que quiero asegurarse de que cada clase que hereda Animal para contener getNumberOfLegs() método (es decir, casi como una interfaz, excepto sí quiero la clase abstracta para implementar varios métodos que son comunes a todas las clases hijas, por lo tanto, la interfaz pura no funciona aquí) getNumberOfLegs(), obviamente, debe haber un método estático (suponiendo que en un mundo perfecto 'no tiene pollo y perros, así getNumberOfLegs no es instancia dependiente paralizado).

Sin un método/campo "abstracto estático", uno puede dejar el método fuera de la clase Animal, entonces existe el riesgo de que algunas clases secundarias no tengan ese método. O uno puede hacer que getNumberOfLegs sea un método de instancia, pero luego tendría que instanciar una clase para averiguar cuántas patas tiene ese animal, aunque no sea necesario.

¿Cómo se suele ir sobre la implementación de esta situación?


EDITAR: Aquí cómo podría utilizar esto. Asumir (ahora esto es ridículo, pero de todos modos ...) que el número de patas de cada animal es único, por lo que podría tener algo como:

Animal getModelAnimal(int numberOfLegs) { 
    if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken(); 
    else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog(); 
} 

Respuesta

3

Su pseudocódigo se parecía mucho a Java, por lo que estoy asumiendo que es Java lo que estás usando.

"Un método abstracto requiere implementación por instancia. Los métodos estáticos pertenecen a una clase general. Un método estático en una clase abstracta pertenece a la clase abstracta, no implementaciones potenciales. Por lo tanto, no tiene sentido permitir la estática abstracta Además, los métodos estáticos no se pueden anular, así que, de nuevo, los métodos estáticos abstractos serían una anomalía ".

De http://forums.sun.com/thread.jspa?threadID=597378

favor también mirar a Why can't I define a static method in a Java interface?

+0

-1: No se puede decir que en general. el método abstracto no siempre es sin sentido (ver mi publicación). – Simon

+0

Edité mi respuesta para reflejar esto. –

+0

Mi pregunta está destinada a ser independiente del lenguaje (me encontré con un problema similar en C# antes). Puedo ver por qué no hay un modificador "estático abstracto" en un idioma, pero estoy más interesado en ver cómo se puede implementar limpiamente el problema que planteé en la pregunta. – polyglot

0

Incluso si usted podría tener un método estático resumen, ¿cómo usarlo? Piense en cómo lo usaría antes de pensar en cómo implementarlo, ya que su implementación debe coincidir con los usos.

+0

@Downvoter: ¿por qué no le digo a la gente cuál es el problema con mi respuesta? –

3

Este es un punto muy bueno ya veces abstract static realmente faltan. Sin embargo, como hoy en día la memoria no es un problema, seguramente puede implementar el método getNumberLegs() como método de instancia.

Decir que es abstracta estática sin sentido, no es cierto. PHP permite métodos estáticos abstractos (ver this) y su escenario muestra que puede ser útil en algunas situaciones.

Tampoco es cierto que static métodos no pueden ser anulados; final métodos no pueden ser anulados. En idiomas como Java y C#, static viene con final. Es por eso que muchos suponen que static es igual a "no anulable".

Hablando de C# (después de leer sus comentarios, supongo que "habla" C#), es posible considerar el uso de genéricos y atributos (o genéricos y anotaciones en Java):

public class Animal 
{ 
    public static int GetNumberOfLegs<T>() where T : Animal 
    { 
    //Get T's custom attribute "NumberOfLegs" and return its value 
    } 

    //EDIT: Added runtime-version of GetNumberOfLegs. 
    public static int GetNumberOfLegs(Type t) 
    { 
    //Get t's custom attribute "NumberOfLegs" and return its value 

    } 
} 

[NumberOfLegs(4)] 
public class Cat { ... }; 

Esto le permitirá para obtener el número de patas de cada tipo sin instanciarlo. Solo recuerde indicar el atributo [NumberOfLegs(x)]. También debe saber el tipo en el momento de la compilación (para la versión genérica del método).

EDIT: He añadido una versión de tiempo de ejecución de la GetNumberOfLegs() -method, a los que puede pasar un objeto Type (debe ser Class para Java). En este caso, tendrá que hacer una verificación de tipo en tiempo de ejecución, es decir, verificar si el tipo representado por el Type -/Class -objeto hereda de Animal y luego recupera el valor pasado en el atributo/anotación.

Uso:

int numberOfLegs1 = Animal.GetNumberOfLegs<Cat>(); 
int numberOfLegs2 = Animal.GetNumberOfLegs(typeof(Cat)); //runtime version 
+0

Comparar Java/C# con PHP es como comparar manzanas con naranjas .. – BalusC

+2

No es una comparación ... Estoy demostrando que la estática abstracta no es sin sentido. Estoy señalando un concepto general de OOP. – Simon

+0

lo siento, pero por sí mismo, la estática abstracta todavía no tiene sentido. Necesitabas un atributo personalizado para dar sentido a este caso de uso. –

2

¿Cómo se suele ir sobre la implementación de esta situación?

En términos de Java, simplemente declararía un constructor en la clase abstracta que toma un argumento fijo. Entonces se requiere que cada subclase lo invoque, de lo contrario no se compilará.

abstract class Animal { 
    private int numberOfLegs; 

    public Animal(int numberOfLegs) { 
     this.numberOfLegs = numberOfLegs; 
    } 

    public int getNumberOfLegs() { 
     return numberOfLegs; 
    } 
} 

class Chicken extends Animal { 
    public Chicken() { 
     super(2); 
    } 
} 

class Dog extends Animal { 
    public Dog() { 
     super(4); 
    } 
} 

actualización: según su actualización

EDIT: He aquí cómo podría utilizar esto. Asumir (ahora esto es ridículo, pero de todos modos ...) que el número de patas de cada animal es único, por lo que podría tener algo como:

Animal getModelAnimal(int numberOfLegs) { 
    if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken(); 
    else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog(); 
} 

Este es de hecho ridícula, esto requiere que todos esos animales concretos se conozcan de antemano en el método abstracto de fábrica. Debería actualizar el método de fábrica abstracta cada vez que se agrega un nuevo tipo de animal concreto. ¿Cuál es el objetivo de la fábrica abstracta entonces? ¿Ya sabes todo de antemano? No, simplemente deje que el método de fábrica abstracta tome el nombre de clase calificado completo como identificador más o menos, para que pueda intentar cargar desde la ruta de clases (aún hablando en términos de Java).

+0

Pero 'getNumberOfLegs()' todavía es un método de instancia y tengo que crear una instancia de las clases para averiguar cuántas patas tiene el animal ... – polyglot

+0

Ver la actualización de mi respuesta. – BalusC

+0

Sin embargo, el método 'getModelAnimal()' no se define necesariamente en la clase Animal. – polyglot

0

Esta es una pregunta interesante. En mi opinión, los métodos de "resumen estático" rara vez se necesitan, y siempre hay buenas alternativas.

En el caso de uso que proporcionó, por ejemplo, el método de fábrica aborda las clases de animales concretas por su nombre; para cada nueva clase de animal, se debe agregar un nuevo código específico. Por lo tanto, parece que la calificación "abstracta" no es realmente necesaria. Una convención de suministro de un método estático getNumberLegs() es suficiente.

Y más en general, la combinación abstracta y estática no tiene sentido (en Java) desde abstracta implica polimorfismo, mientras estáticas llamadas no son polimórficos en absoluto, y el trabajo en clases conocidas en tiempo de compilación.

4

¿Cómo se suele ir sobre implementando esta situación?

La solución habitual es hacer que el método en cuestión sea un método de instancia.

getNumberOfLegs(), obviamente, debe haber un método estático (suponiendo que en un mundo perfecto nosotros no' han paralizado pollo y perros, así getNumberOfLegs es no instancia dependiente).

Eso es enfáticamente not obvio! No programamos para un mundo perfecto, y en el mundo real, los animales de cuatro patas a veces tienen una, dos o tres (o cinco) patas.

Si el programa necesita animales definiciones en lugar de animales casos, seguir adelante y hacer una clase para la que .

class AnimalDefinition { 
    public string getScientificName(); 
    public string getCommonName(); 
    public int getNumberOfLegs(); 
    public bool getIsAmphibious(); 
    // etc. 
} 

Entonces inicializar una colección de los del inicio de su programa - idealmente de una base de datos o un archivo de configuración donde puede añadir definiciones de animales sin necesidad de escribir o la compilación de otra línea de código. (Y que puede salirse con muchos menos tipos.)

0

Usted podría cludge un tiempo de ejecución comprobación de que el método se implementa por tener su clase base una excepción en su aplicación. No vale mucho, pero quizás mejor que nada ...

0

Los métodos abstractos tienen sentido si los llamas en ayuda de la clase base. Tenga en cuenta que en su ejemplo, no está utilizando polimorfismo en absoluto. En el ejemplo debería ser algo como:

(Animal)Dog.getNumberOfLegs() //cast Dog to Animal first 

De todos modos PHP objetivo la aplicación de los llamados "tarde estática vinculante", que es probablemente lo que busca

http://php.net/manual/en/language.oop5.late-static-bindings.php

En una funcionalidad similar en C++ se puede lograr usando tamplates y polimorfismo en tiempo de compilación.

0

abstract static métodos solo tienen sentido en los idiomas en los que las variables pueden contener tipos reales y no solo instancias. (Delphi es uno de esos lenguajes, C# no lo es, y tampoco creo que puedas hacerlo en Java). La razón es que si sabes en tiempo de compilación exactamente qué clases estás usando (como en tu ejemplo), entonces no hay ninguna razón para que el método sea abstract, podrías tener static métodos en cada clase con el mismo nombre cosas. La única manera en que posiblemente no sepas qué tipos estás utilizando es si puedes asignar tipos a una variable, ya que puedes pasarlos (como instancias de clases) y de repente todo tiene sentido y es útil.

creo que la mayoría de los compiladores/lenguajes que soportan la asignación de tipos (así como instancias de tipos) a las variables también se las arreglan para apoyar abstract static y virtual abstract métodos a través de la magia del compilador, por lo que si en realidad son útiles en el idioma de su elección, entonces se debe ser compatible.

+0

No solo idiomas con tipos de variables. Otro caso es cuando se llama a ese método estático abstracto desde otro método. Digamos que uno de los métodos de Animal llama 'Animal.getNumberOfLegs()'. Entonces puede llamar a Dog en uno de sus métodos este método. Dado que 'getNumberOfLegs()' es abstracto 'Animal.getNumberOfLegs()' dentro del cuerpo del método de Animal, podría enviarse a 'Dog.getNumberOfLegs()'. – doc

+0

Ese ejemplo no tiene sentido. ¿Cómo se supone que el compilador debe saber que debe enviar una llamada estática a otro tipo en función de la firma de la llamada no estática en la que se encuentra actualmente? Así no es como funcionan estas cosas. – Donnie

+0

Creo que vtable adicional para llamadas estáticas debería hacer el trabajo. De todos modos, depende solo de RTTI. PHP hace algo así (aunque no exactamente). – doc

0

un enfoque más que puedo ver aquí es hacer una fábrica abstracta: esto es C# no es necesario hacer una instancia de pollo para conocer un número de patas. simplemente invocar el método de fábrica checken

abstract class AnimalFactory 
{ 
    public abstract Animal CreateAnimal(); 
    public abstract int GetLegs(); 

} 
abstract class Animal 
{ 

} 
internal class Chicken : Animal 
{ 

} 
class CreateChicken : AnimalFactory 
{ 
    public override Animal CreateAnimal() 
    { 
     return new Chicken(); 
    } 
    public override int GetLegs() 
    { 
     return 2; 
    } 

} 
0

Por un momento, asumen "métodos estáticos abstractas" son permitidos.

Luego, utilizando su código, añado esto:

Animal modelAnimal; 
int numLegs; 

modelAnimal = this.getModelAnimal(4); // Got a dog 

numLegs = modelAnimal.getNumberOfLegs(); 

voy a conseguir el error como modelAnimal que es un objetoperro intentará llamar getNumberOfLegs en Animal clase y no Clase de perro. No anula los métodos estáticos que conoce. Para evitar esta situación, los diseñadores no han incluido métodos estáticos abstractos.

Cuestiones relacionadas