2009-02-06 28 views
15

¿Cómo puede el polimorfismo reemplazar una instrucción if-else o Switch dentro de un bucle? En particular, ¿siempre puede reemplazar un if-else? La mayoría de los if-thens que uso dentro de los bucles son comparaciones aritméticas. Esta pregunta se genera a partir de este question.¿Cómo puede el polimorfismo reemplazar una instrucción if-else dentro de un ciclo?

int x; 
int y; 
int z; 

while (x > y) 
{ 
    if (x < z) 
    { 
     x = z; 
    } 
} 

¿Cómo funcionaría esto con el polimorfismo?
NOTA: escribí esto en Java pero estoy interesado en esto para cualquier OOL.

+0

@ken Gracias por detectar el error tipográfico. Lo hago mucho. – WolfmanDragon

Respuesta

24

El polimorfismo generalmente reemplaza las declaraciones de cambio cuando cada caso corresponde a un tipo diferente. Así que en lugar de tener:

public class Operator 
{ 
    string operation; 

    public int Execute(int x, int y) 
    { 
     switch(operation) 
     { 
      case "Add": 
       return x + y; 
      case "Subtract": 
       return x - y; 
      case "Multiply": 
       return x * y; 
      case "Divide": 
       return x/y; 
      default: 
       throw new InvalidOperationException("Unsupported operation"); 
     } 
    } 
} 

Tendrías:

public abstract class Operator 
{ 
    public abstract int Execute(int x, int y); 
} 

public class Add : Operator 
{ 
    public override int Execute(int x, int y) 
    { 
     return x + y; 
    } 
} 

// etc 

Sin embargo, para el tipo de comparación entre la resolución que ya ha proporcionado, el polimorfismo realmente no ayuda.

3

El polimorfismo no es realmente aplicable en el ejemplo que proporcionó.

Ver esto SO answer.

+0

Si fuera Smalltalk en lugar de java, el ejemplo ya sería polimórfico. –

+0

... ¡pero no es Smalltalk! –

+0

La pregunta es independiente del idioma. Una traducción directa del código en smalltalk sería polimórfica. –

3

El polimorfismo solo puede reemplazarse si se realizan pruebas cuando la prueba if se realiza básicamente en una variedad de métodos, dependiendo del "tipo" de un objeto. Por ejemplo, si el objeto es tipo X, invoque a foo si es una barra de invocación Y y así. En este ejemplo artificial uno definiría una interfaz DoSonething con un método bad(). Tanto X como Y implementarían Baz y harían que sus respectivos baz() invoquen foo() para X y bar() para Y. Esto simplemente llamando a baz() eliminaría la necesidad de una prueba if.

3

En Smalltalk, "si" es realmente un método polimórfico en Boolean. En el siguiente ejemplo:

[ x>y ] whileTrue: 
    [ 
    (x<z) ifTrue: [ x:=z ]   
    ] 

El mensaje ifTrue:aBlock se implementa en True como "ejecutar este bloque" y en False como "ignorar este bloque", así que dependiendo de lo que el (x<z) evalúa a, o bien la aplicación se llamará.

Así que en Smalltalk polimorfismo reemplaza cada if-else construir por defecto :)

+0

Divulgación: nunca he usado smalltalk. ¿Todavía no hay un valor booleano aquí? Si es así, ¿no es simplemente una declaración de lujo IF-Then-Else envuelta en polimorfismo? Solo estoy pidiendo una aclaración. – WolfmanDragon

+0

Sí, hay un valor booleano y es una declaración if-then-else implementada mediante polimorfismo. Soy consciente de que este polimorfismo ocurre en un nivel diferente al de la pregunta, pero creo que el mecanismo sigue siendo lo suficientemente interesante como para justificar esta respuesta. –

1

Un patrón es tener objetos que representan el resultado de la prueba, y los objetos que representan el bloque a ejecutar. Los objetos resultantes han anulado las funciones de selección, por lo que si Bool tuviera una opción (T positivo, T negativo), entonces Bool.TRUE devolvería el argumento positivo y Bool.FALSE devolvería el negativo. Las implementaciones ingenuas de los lenguajes de la familia smalltalk funcionan así.

Para codificar su ciclo while de esa forma, necesita llamar al método choose sobre el resultado de comparar xey para determinar si se llama al bloque dentro del ciclo while, y ese bloque también usa compare y elige establecer el valor de x. Una traducción más literal sería elegir ya sea un bloque que establece x a z o uno que no hace nada; en su lugar, solo utiliza elegir establecer x de nuevo en el mismo valor.

Obviamente, es excesivo e ineficiente en este caso simple.

public class WantonPolymorphism { 

    static class Int32 { 
     final int value; 
     Int32 (final int value) { this.value = value; } 

     Compare compare (Int32 other) { 
      // Java runs out of turtles at this point unless you use 
      // an enum for every value 
      if (this.value < other.value) return Compare.LESS; 
      if (this.value > other.value) return Compare.GREATER; 
      return Compare.EQUAL; 
     } 
    } 

    enum Compare { 
     LESS { 
      <T> T choose (T less, T equal, T greater) { return less; } 
     }, 
     EQUAL { 
      <T> T choose (T less, T equal, T greater) { return equal; } 
     }, 
     GREATER { 
      <T> T choose (T less, T equal, T greater) { return greater; } 
     }; 

     abstract <T> T choose (T less, T equal, T greater) ; 
    } 

    interface Block { Block execute() ; } 


    /** 
    * Main entry point for application. 
    * @param args The command line arguments. 
    */ 
    public static void main (String...args) { 
     Block block = new Block() { 
      Int32 x = new Int32(4); 
      Int32 y = new Int32(3); 
      Int32 z = new Int32(2); 

      public Block execute() { 
       System.out.printf("x = %d, y = %d, z = %d\n", x.value, y.value, z.value); 

       return x.compare(y).choose(done, done, new Block() { 
        public Block execute() { 
         x = x.compare(z).choose(x,x,z); 

         return x.compare(y).choose(done, done, this); 
        } 
       }); 
      } 

      Block done = new Block() { 
       public Block execute() { 
        System.out.printf("x = %d, y = %d, z = %d\n", x.value, y.value, z.value); 
        System.exit(0); 
        return this; 
       } 
      }; 
     }; 

     for(;;) 
      block = block.execute(); 
    } 
} 
+0

+1 para el concepto. Sin embargo, todavía hay declaraciones. – WolfmanDragon

0

Para primitivo no podemos, pero para el objeto sí podemos.

mira esto blog.

Cuestiones relacionadas