El título puede ser confuso, pero, por favor, mira el siguiente patrón

public abstract class Animal
{

    public abstract Dog GetDog { get; }

    public abstract Cat GetCat { get; }

}

public class Dog : Animal
{

    public override Dog GetDog {
        get { return this; }
    }

    public override Cat GetCat {
        get { return null; }
    }

}

Es que esto se considera una mala práctica que tiene propiedades en la clase base, el retorno a los tipos derivados. O debo hacer algo como

public abstract AnimalTypeEnum AnimalType { get; }

EDIT: con Base en los comentarios, supongo que debería ser más claro en lo que estoy tratando de lograr. Una nueva instancia de la Dog o Cat clase se puede crear una función específica, basada en ciertos criterios y regresaba Animal tipo a la persona que llama. El método de llamada marque el tipo de la devolución de la instancia y su uso adecuado.

public Animal CreateAnimal(string path)
{

    //Process the document in path and create either a new instance of dog or cat

    Dog dg = new Dog();

    return dg;

}
  • Lo que estás meta final en hacer esto?
  • Que no contesta la pregunta. ¿De qué manera estos métodos en realidad se puede utilizar?
  • Bueno… pero ¿cuál es el punto? Perro no debe tener un método para conseguir un gato, incluso si se trata de devolver null. Lo que está mal con Animal dog = new Dog()?
  • Me gustaría volver a la clase base de una función y el método de la llamada a la función sería entonces echó a los correspondientes derivados de tipo de
  • Pero si usted va a echar el tiempo, no que derrota el punto de heredar de una clase base?
  • A mí me parece que usted está tratando de proporcionar una sintaxis alternativa para Dog dog = animal as Dog;. En general se debe evitar que su clase base que saber acerca de las clases derivadas – de lo contrario, para agregar una nueva clase derivada tiene que cambiar la clase base es bastante desordenado.
  • ¿Por qué el perro necesita un método GetCat, o un gato en un método GetDog? Que una rápida señal de que algo no se haga con el diseño y la prob de la violación de un lsp.

InformationsquelleAutor swiftgp | 2012-10-18

5 Comentarios

  1. 7

    El método de llamada marque el tipo de la devolución de la instancia y su uso adecuado.

    Ahí está el problema. Es de código olor a tener que hacer eso. Usted debe ser capaz de tratar lo que es tan sólo un objeto, en lugar de tratar a los perros y gatos de manera diferente.

    Si usted necesita para mostrar el contenido de los animales, a continuación, reemplazar el ToString método en ambas clases y sólo llamar ToString de los animales. Si usted necesita saber el nombre del perro o del gato, a continuación, agregue un Name propiedad Animal. Si es posible, usted debe utilizar el polimorfismo de aquí, así que todo lo que está utilizando el objeto de las huellas como un Animal, y consiste simplemente en diferentes cosas que suceden como resultado de las diferentes implementaciones de un mismo método.

    Si usted realmente, realmente necesita saber si el Animal es un Dog o un Cat a continuación, puede utilizar el is o as operadores; no es necesario añadir todo el código que has mostrado en la OP.

    • La clase base tiene un montón de funcionalidad que es común a los tipos derivados, los derivados de tipos de ampliarlo un poco más. Cuando el CreateAnimal se llama a la función, ya sea un Cat tipo o Dog tipo de necesidades a ser creado dinámicamente y no hay forma de saber qué tipo debe ser creado antes de la mano. Así que me gustaría realmente necesita para devolver el mínimo garantizado de tipo y también ofrecen opciones si quieren hacer un poco más.
    • Sí, la CreateAnimal método está muy bien; no estoy sugiriendo que usted la cambie. Estoy diciendo que usted debe ser capaz de hacer lo que tiene que hacer con el Animal que se devuelve sin hacer algo que se traduce en un Cat o Dog instancia. Aunque puede haber una situación en la que realmente no puede hacer eso, usted debe estar muy seguro antes de ir por ese camino. Si tienes que ir por ese camino, como he dicho, debe utilizar is o as más que el concepto que usted ha creado.
    • Incluso suponiendo que usted necesita para saber si se trata de un Cat o un Dog específicamente, se podría reemplazar todo lo que prueba que estaba pensando en usar con is.
    • Estoy de acuerdo en la Is parte y no necesariamente necesita saber si se trata de un Cat o Dog para llamar a métodos en Animal, mientras que yo tendría que conocer el tipo de llamar a determinados métodos en los tipos derivados que son válidas para un tipo diferente. Hay otros enfoques?
    • if (animal is Cat) { ((Cat)animal).Meow(); } else if (animal is Dog) { ((Dog)animal).Bark(); } else { throw new TypeException(); }. Todavía no entiendo por qué usted no puede mover la lógica de creación de CreateAnimal() en su código de llamada, aunque.
    • Te he mostrado sólo un ejemplo perfecto de lo que no debería estar haciendo. En lugar de tener un gato maullar o el ladrido de un perro, usted debe agregar algo como Speak a Animal que cualquiera de los ladridos o maullidos, dependiendo del tipo de la clase derivada.
    • Mi punto es que usted no debería tener sólo métodos en la clase derivada que usted necesita para su uso en este contexto. Si va a crear el animal de un método general, cualquier código con el que no debería tener que hacer algo que es específico de uno solo. En la mayoría de los casos esto significa que cualquiera que sea la función que desea utilizar debe ser definida simplemente en Animal, incluso si la aplicación para perro o gato no hacer nada.
    • De acuerdo. El uso de ese código sería mal, pero el uso de la OP del código sería peor. Es una situación que desesperadamente llamadas para la refactorización.
    • Lo que si Cat necesita un método llamado LookCute que no es sólo válido para Dog. Típicamente, que todavía debe definir en el Animal clase. Yo no soy difícil, solo estoy tratando de aprender y no entiendo el voto negativo.
    • Si usted necesita tener una LookCute método para sólo los gatos, entonces no debería ser llamada en un objeto que se devuelve a partir de un método que puede o no puede ser un gato. Usted sólo debe llamar a LookCute en algo que, desde el principio, usted sabe que va a ser capaz de mirar lindo.

  2. 12

    Si desea que el animal va a derivar de usted puede hacer esto:

    public abstract class Animal<T> where T: Animal<T>
    {
        public T GetAnimal 
        {
            get { return (T)this; }
        }
    }
    
    public class Dog : Animal<Dog>
    {
    }
    
    public class Cat : Animal<Cat>
    {
    }
    
    public class Giraffe : Animal<Giraffe>
    {
    }

    Llamar de esta manera:

    var cat = new Cat();
    var dog = new Dog();
    var giraffe = new Giraffe();
    Cat cat2 = cat.GetAnimal;
    Dog dog2 = dog.GetAnimal;
    Giraffe giraffe2 = giraffe.GetAnimal;
    • Aunque creo que esta es la mejor solución que C# genéricos nos da, sólo tenga en cuenta que es posible hacer public class Rat : Animal<Dog> { } que compile bien y luego volar al llamar new Rat().GetAnimal
    • Buena solución. Gracias!
  3. 5

    Nah estás haciendo mal.

    Lo mejor sería tener un solo método.

    public abstract Animal getAnimal();

    Cualquier clase derivada, a continuación, sabrá cómo volver en sí. Espero que tenga sentido. Pero entonces yo no creo que usted querrá volver a un Animal cualquiera. No tiene sentido.

    Animal dog = new Dog() ;
    dog.getAnimal(); 

    confuso a la derecha?

    Usted puede tener una variedad de Animales/Lista de iterar a través de la recopilación y verificación, así:

    if(animal is Dog)

    Pero todavía se comprobar el tipo. Si desea utilizar una clase base que lo que tiene sentido y expone un método común.

  4. 1

    Esto es realmente una bas diseño, ya que viola el Abierto-Cerrado de principio. Usted quiere que sus clases de estar abierto a la extensión, pero cerrado a la modificación.
    ¿Qué pasará si mañana usted querrá agregar otra clase?

    public class Donkey : Animal
    {
    }

    Usted tendrá que ir y cambiar la clase base, de manera que tenga una propiedad GetDonkey.
    Usted también tendrá que ir y cambiar todas las clases que utiliza la clase y agregar if (animal.GetDonkey == null)

    Lo que usted debe hacer es usar una fábrica de patrón de diseño como este:

    public static class AnimalFactory
    {
      public static Dog GetDog()
      {
        return new Dog();
      }
    
      public static Cat GetCat()
      {
        return new Cat();
      }
    }

    o debería utilizar un método virtual como @Lews Therin sugerido.

    • Usted menciona no debería ser un GetDonkey() pero tiene un GetDog()?
  5. -2

    No parece muy útil tener propiedades que acaba de devolver el objeto al que estamos llamados.

    Tal vez sólo estás buscando una manera para abatido de una superclase a una subclase? Si es así, sólo tiene que utilizar moldes:

    Animal a = new Cat();
    
    try
    {
        Dog d = (Dog)a;
    }
    catch (InvalidCastException)
    {
        try
        {
            Cat c = (Cat)a;
        }
        catch (InvalidCastException)
        {
        }
    }
    • Usted no debe usar excepciones para el control de flujo. is y as están diseñados para hacer esto sin generar excepciones.
    • solución creativa, pero un poco exagerado 🙂
    • De acuerdo con @Servy que este es un mal diseño. Sin embargo, ahora se puede lograr algo muy similar en la función (sin todo el try/catch tonterías) utilizando el interruptor de la declaración de reconocimiento de patrones.

Dejar respuesta

Please enter your comment!
Please enter your name here