2009-02-06 1 views
15

Как полиморфизм может заменить инструкцию if-else или включить внутри цикла? В частности, может ли он всегда заменять if-else? Большинство из if-thens, которые я использую внутри циклов, являются арифметическими сравнениями. Этот вопрос порожден из этого question.Как полиморфизм может заменить инструкцию if-else внутри цикла?

int x; 
int y; 
int z; 

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

Как это работает с полиморфизмом?
ПРИМЕЧАНИЕ: Я написал это на Java, но я заинтересован в этом для любого OOL.

+0

@ken Благодарим вас за ловушку. Я делаю это много. – WolfmanDragon

ответ

24

Полиморфизм обычно заменяет операторы switch, когда каждый случай соответствует другому типу. Поэтому вместо того, чтобы:

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"); 
     } 
    } 
} 

вы бы:

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 

Однако для сравнения типа решения вы предоставили, полиморфизм действительно не помогает.

3

Полиморфизм на самом деле не применим в примере, который вы предоставили.

См. Это SO answer.

+0

Если бы это был Smalltalk скорее, чем java, то пример уже был бы полиморфным. –

+0

... но это не Smalltalk! –

+0

Вопрос не является агностиком. Прямой перевод кода в smalltalk был бы полиморфным. –

3

Полиморфизм может заменить только те тесты, когда тест if в основном отправляется на различные методы в зависимости от типа объекта. Например, если объект является типом X, вызовите foo, если это строка вызова Y и так далее. В этом надуманном примере можно было бы определить интерфейс DoSonething с методом bad(). И X, и Y будут реализовывать Baz и иметь их baz() для вызова foo() для X и bar() для Y. Это простое вызов baz() устранит необходимость в тесте if.

3

В Smalltalk «if» на самом деле является полиморфным методом в буле. В следующем примере:

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

ifTrue:aBlock сообщение реализуется в True как «выполнить этот блок» и в False как «игнорировать этот блок», поэтому в зависимости от того, что (x<z) имеет значение, либо реализация будет называться.

Таким образом, в Smalltalk полиморфизм заменяет каждый, если-иначе построить по умолчанию :)

+0

Раскрытие информации: Я никогда не использовал smalltalk. Не существует ли здесь булевского значения? Если да, то это просто не фантастический оператор IF-Then-Else, завернутый в полиморфизм? Я просто прошу разъяснений. – WolfmanDragon

+0

Да, существует логическое значение, и это выражение if-then-else, реализованное через полиморфизм. Я знаю, что этот полиморфизм происходит на другом уровне, чем тот, который от вопроса, но я думаю, что механизм все еще достаточно интересен, чтобы оправдать этот ответ. –

1

Один образец должен иметь объекты, которые представляют собой результат теста, а также объекты, которые представляют собой блок для выполнения. Объекты результата имеют переопределенные функции выбора, поэтому, если у Bool был выбран (T положительный, отрицательный T), тогда Bool.TRUE вернет положительный аргумент, а Bool.FALSE вернет отрицательный результат. Наивные реализации небольших семейных языков работают так.

Чтобы закодировать цикл while в этой форме, необходимо вызвать метод select в результате сравнения x и y, чтобы определить, следует ли вызывать блок для внутреннего цикла while, и этот блок также использует сравнение и выберите значение x. Более буквальным переводом было бы выбрать либо блок, который устанавливает x в z, либо тот, который ничего не делает; вместо этого он просто использует, чтобы установить x обратно на одно и то же значение.

Очевидно, что это излишне и неэффективно для этого простого случая.

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 для концепции. Тем не менее, есть утверждения. – WolfmanDragon

0

Для примитивных мы не можем, но для объекта да мы можем.

этот blog.