Можете ли вы написать какой-либо алгоритм без оператора if? - PullRequest
30 голосов
/ 21 декабря 2009

Этот сайт щекотал мое чувство юмора - http://www.antiifcampaign.com/ но может ли полиморфизм работать в каждом случае, когда вы используете оператор if?

Ответы [ 18 ]

39 голосов
/ 21 декабря 2009

Smalltalk, который считается «действительно» объектно-ориентированным языком, не имеет оператора «if» и не имеет оператора «for», оператора «while». Есть и другие примеры (например, Haskell), но это хороший пример.

Цитирование В Smalltalk нет оператора «если» :

Некоторые из зрителей могут думать что это свидетельство, подтверждающее их подозрения, что Smalltalk странный, но я скажу вам, что это:

Оператор «if» - это мерзость в объектно-ориентированном языке.

Почему? Ну, язык ОО составлен классов, объектов и методов, и утверждение «если» неизбежно из тех. Вы не можете написать «если» в Оо путь. Этого не должно быть. Условное исполнение, как и все иначе должен быть метод. Метод что? Boolean.

Теперь, как ни странно, в Smalltalk, Boolean имеет метод с именем ifTrue: ifFalse: (это имя будет выглядеть довольно странно сейчас, но передайте это для сейчас). Это абстрактно в логическом, но Boolean имеет два подкласса: True и Ложь. Метод передается двумя блоками кода. В True метод просто запускает код для истинного случая. В Ложь, он запускает код для ложного дело. Вот пример, который, мы надеемся, объясняет:

(x >= 0) ifTrue: [
'Positive'
] ifFalse: [
'Negative'
]

Вы должны увидеть ifTrue: и ifFalse: там. Не волнуйся что они не вместе.

Выражение (x> = 0) оценивается как правда или ложь. Скажи, что это правда, тогда мы есть:

true ifTrue: [
'Positive'
] ifFalse: [
'Negative'
]

Я надеюсь, что довольно очевидно, что это даст "Позитив".

Если бы это было ложно, у нас было бы:

false ifTrue: [
'Positive'
] ifFalse: [
'Negative'
]

Это производит "Негатив".

Хорошо, вот как это делается. Что так здорово об этом? Ну во что другое язык вы можете сделать это? Больше серьезно, ответ таков: никаких особых случаев в этом язык. Все можно сделать за Оо путь, и все сделано в Оо путь.

Я определенно рекомендую прочесть весь пост, а Код также является объектом того же автора.

39 голосов
/ 21 декабря 2009

answer: ** Этот веб-сайт против использования операторов if для ** проверки наличия у объекта определенного типа. Это полностью отличается от if (foo == 5). Плохо использовать if как if (foo instanceof pickle) Альтернатива, использующая вместо этого полиморфизм, способствует инкапсуляции, бесконечно облегчая отладку, сопровождение и расширение кода.

Быть против if в целом (выполнение определенной вещи, основанной на условии) ничего не даст вам. Обратите внимание, как все остальные ответы здесь все еще принимают решения, так в чем же разница?

объяснение причины полиморхишма:

Возьмите эту ситуацию:

void draw(Shape s) {
    if (s instanceof Rectangle)
        //treat s as rectangle
    if (s instanceof Circle)
        //treat s as circle
}

Намного лучше, если вам не нужно беспокоиться о конкретном типе объекта, обобщая, как объекты являются процессами.

void draw(Shape s) {
    s.draw();
}

Это перемещает логику того, как нарисовать фигуру в самом классе фигуры, поэтому теперь мы можем обрабатывать все фигуры одинаково. Таким образом, если мы хотим добавить новый тип фигуры, все, что нам нужно сделать, это написать класс и дать ему метод draw вместо изменения каждого условного списка во всей программе.

Эта идея сегодня встречается повсеместно в программировании, вся концепция интерфейсов полностью связана с полиморфизмом. (Shape - это интерфейс, определяющий определенное поведение, позволяющий нам обрабатывать любой тип, который реализует интерфейс Shape в нашем методе.) Динамические языки программирования продвигаются дальше, позволяя нам передавать в метод любой тип, который поддерживает необходимые действия. Что выглядит лучше для вас: (псевдокод в стиле Python)

def multiply(a,b):
    if (a is string and b is int):
        //repeat a b times.
    if (a is int and b is int):
        //multiply a and b

или используя полиморфизм:

def multiply(a,b):
    return a*b

Теперь вы можете использовать любые 2 типа, которые поддерживают оператор *, что позволяет использовать метод с типами, которые еще не были созданы.

См. полиморфизм , что такое полиморфизм в стеке потока

7 голосов
/ 21 декабря 2009

Хотя это и не связано с ООП: в Прологе единственный способ написать все ваше приложение - без операторов if.

6 голосов
/ 21 декабря 2009

Да, на самом деле, вы можете иметь язык, полный тьюринга, который не имеет по себе «if» и допускает только операторы «while»:

http://cseweb.ucsd.edu/classes/fa08/cse200/while.html

Что касается ОО-дизайна, то в некоторых случаях имеет смысл использовать шаблон наследования, а не переключатели, основанные на поле типа ... Это не всегда возможно или обязательно желательно.

@ ennuikiller: условные выражения - это просто синтаксический сахар:

if (test) body;     is equivalent to    x=test; while (x) {x=nil; body;}

if-then-else более многословно:

if (test) ifBody; else elseBody;

is equivalent to

x = test; y = true;
while (x) {x = nil; y = nil; ifBody;}
while (y) {y = nil; elseBody;}

Примитивная структура данных представляет собой список списков. Можно сказать, что 2 скаляра равны, если они являются списками одинаковой длины. Вы могли бы зациклить их одновременно, используя операторы head / tail и посмотреть, останавливаются ли они в одной и той же точке.

конечно, все это можно обернуть в макросы.

Самым простым языком тьюринга, вероятно, является йота . Он содержит только 2 символа («i» и «*»).

6 голосов
/ 28 декабря 2012

Аргументация кампании «против-если» похожа на то, что сказал Кент Бек:

Хороший код всегда имеет небольшие методы и маленькие предметы. Только разделив систему на множество маленьких кусочков и функционировать можете ли вы надеяться удовлетворить правило «один раз и только один раз». Я получаю много сопротивления этой идее, особенно от опытных разработчиков, но никто то, что я делаю с системами, помогает так же сильно, как разбивает его на несколько частей.

Если вы не знаете, как составлять и наследовать программу, то ваши классы и методы со временем будут расти. Когда вам нужно внести изменения, проще всего будет добавить где-нибудь IF. Добавьте слишком много IF, и ваша программа будет становиться все менее и менее обслуживаемой, и все же проще всего будет добавить больше IF.

У вас нет , чтобы превратить каждый IF в объектную совместную работу; но это очень хорошо, когда ты умеешь: -)

6 голосов
/ 21 декабря 2009

Да. Заявления if подразумевают филиалы, которые могут быть очень дорогостоящими для многих современных процессоров, особенно для PowerPC. Многие современные ПК выполняют много конвейерного переупорядочения, и поэтому ошибочные прогнозы ветвления могут стоить порядка 30 циклов на одно ветвление.
В консольном программировании иногда быстрее просто выполнить код и проигнорировать его, чем проверить, следует ли его выполнять!

Простой обход ветвей в C:

if (++i >= 15)
{
    i = 0;
)

можно переписать как

 i = (i + 1) & 15;  

Однако, если вы хотите увидеть настоящий фу анти-if, прочитайте this

Да, а по вопросу ООП - я заменю неверное предсказание ветвления вызовом виртуальной функции? Нет, спасибо ....

3 голосов
/ 21 декабря 2009

Вы можете определить True и False с объектами (в псевдопионе):

class True:
    def if(then,else):
        return then
    def or(a):
        return True()
    def and(a):
        return a
    def not():
        return False()

class False:
    def if(then,else):
        return false
    def or(a):
        return a
    def and(a):
        return False()
    def not():
        return True()

Я думаю, что это элегантный способ создания логических выражений, и это доказывает, что вы можете заменить каждый if полиморфизмом if, но это не является целью кампании против if. Цель состоит в том, чтобы избежать написания таких вещей, как (в алгоритме поиска пути):

if type == Block or type == Player:
    # You can't pass through this
else:
    # You can

Но лучше вызвать метод is_traversable для каждого объекта. В некотором смысле это как раз обратное сопоставление с образцом. «если» полезно, но в некоторых случаях это не лучшее решение.

3 голосов
/ 21 декабря 2009

Я предполагаю, что вы на самом деле спрашиваете о замене операторов if, которые проверяют типы, в отличие от замены всех операторов if.

Для замены if на полиморфизм требуется метод в общем супертипе, который вы можете использовать для диспетчеризации, либо переопределив его напрямую, либо повторно используя переопределенные методы, как в шаблоне посетителя.

Но что, если такого метода не существует, и вы не можете добавить его к общему супертипу, потому что вы не поддерживаете супертипы? Вы бы действительно пошли на то, чтобы ввести новый супертип вместе с подтипами, чтобы избавиться от единственного if? На мой взгляд, это немного отнимает чистоту.

Кроме того, оба подхода (прямое переопределение и шаблон посетителя) имеют свои недостатки: прямое переопределение метода требует реализации вашего метода в тех классах, которые вы хотите включить, что может не помочь сплоченности. С другой стороны, шаблон посетителя неудобен, если несколько случаев используют один и тот же код. Если вы можете сделать:

if (o instanceof OneType || o instanceof AnotherType) {
    // complicated logic goes here
}

Как бы вы поделились кодом с шаблоном посетителя? Вызовите общий метод? Куда бы вы положили этот метод?

Так что нет, я не думаю, что замена таких операторов if - это всегда улучшение. Часто, но не всегда.

2 голосов
/ 27 мая 2012

Вы можете избежать использования if в своем коде бизнес-логики, если сохраните их в своем коде построения (заводы, застройщики, поставщики и т. Д.). Ваш код бизнес-логики был бы намного более читабельным, легче для понимания или легче поддерживать или расширять. Смотри: http://www.youtube.com/watch?v=4F72VULWFvc

2 голосов
/ 21 декабря 2009

Я часто писал код, как рекомендовано в кампании против if , используя обратные вызовы в словаре делегатов или полиморфизм.

Это довольно привлекательный аргумент, особенно если вы имеете дело с грязными основами кода, но, честно говоря, хотя он отлично подходит для модели плагинов или упрощает большие вложенные операторы if, он делает навигацию и читабельность немного болезненными. 1005 *

Например, F12 (Перейти к определению) в Visual Studio приведет вас к абстрактному классу (или, в моем случае, к определению интерфейса).

Это также делает быстрое визуальное сканирование класса очень громоздким и добавляет накладные расходы при настройке делегатов и поисковых хешей.

Использование рекомендаций, выдвинутых в рамках кампании «анти-if», в той мере, в какой они рекомендуются, выглядит для меня как программирование «о, новая блестящая вещь».

Что касается других конструкций, выдвинутых в этой теме, хотя это было сделано в духе забавного вызова, они просто заменяют утверждение if и на самом деле не обращаются к основным убеждениям анти-if кампании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...