Как полиморфизм может заменить оператор if-else внутри цикла? - PullRequest
17 голосов
/ 06 февраля 2009

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

int x;
int y;
int z;

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

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

Ответы [ 6 ]

25 голосов
/ 06 февраля 2009

Полиморфизм обычно заменяет операторы 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 голосов
/ 06 февраля 2009

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

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

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

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

3 голосов
/ 06 февраля 2009

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

3 голосов
/ 06 февраля 2009

Полиморфизм не очень применим в приведенном вами примере.

См. ТАК ответ .

1 голос
/ 06 февраля 2009

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

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

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

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 голосов
/ 03 мая 2015

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

отметьте это блог .

...