Подтвердить что ты не робот

Избегать, если заявления

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

Я понимаю, что это кажется экстремальным, но кажется, что вы можете попытаться в какой-то мере спорить. Любые мысли об этом?

ИЗМЕНИТЬ

Ничего себе это не заняло много времени. Я полагаю, это слишком экстремально. Можно ли сказать, что при ООП вы должны ожидать меньше, если заявления?

SECOND EDIT

Что об этом: объект, который определяет реализацию своего метода на основе его атрибутов. То есть вы можете реализовать someMethod() двумя способами и указать некоторые ограничения. В любой момент объект будет маршрутизироваться к правильной реализации метода на основе его свойств. Поэтому в случае if(x > 5) есть только два метода, которые полагаются на атрибут x

4b9b3361

Ответ 1

Я могу сказать вам одно. Независимо от того, что говорят люди, мышление об упрощении и устранении ненужного ветвления является признаком того, что вы созреваете как разработчик программного обеспечения. Существует много причин, почему ветвление плохое, тестирование, обслуживание, более высокий уровень ошибок и т.д. Это одна из вещей, которую я ищу при опросе людей, и является отличным показателем того, насколько зрелым они являются разработчиком. Я бы посоветовал вам продолжать экспериментировать, упрощать свой код и дизайн, используя меньшее количество условий. Когда я сделал этот переключатель, я нашел гораздо меньше времени для отладки моего кода, он просто работал, а затем, когда мне пришлось что-то менять, изменения были очень легко сделать, поскольку большая часть кода была последовательной. Опять же, я бы посоветовал вам 100% продолжать делать то, что вы делаете, независимо от того, что говорят другие. Имейте в виду, что большинство разработчиков работают и думают на гораздо более низком уровне и просто следуют правилам. Так хорошая работа, воспитывающая это.

Ответ 2

Объясните, как реализовать следующее без оператора if или тройной логики:

if ( x < 5 ) {
   x = 0
} else {
   print x;
}

Ответ 3

Да, это правда, что часто сложные условности можно упростить с помощью полиморфизма. Но это не всегда полезно. Пойдите, прочитайте книгу Рефакторинга Фаулера, чтобы понять, когда.

http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html

Ответ 4

Полностью устранить, если утверждения не реалистичны, и я не думаю, что это то, что предлагает Ori. Но их часто можно заменить полиморфизмом. (И так может много операторов switch).

Франческо Сирильо начал кампанию против рекламы, чтобы повысить осведомленность об этой проблеме. Он говорит:

Зная, как использовать объекты, разработчики могут исключать IF на основе типа, которые чаще всего компрометируют гибкость программного обеспечения и способность развиваться.

Вы или ваша команда также можете присоединиться к кампании.

Ответ 5

Один из моих учителей говорил это. Я склонен думать, что люди, которые настолько догматичны в отношении такого рода вещей, обычно не зарабатывают на жизнь.

Ответ 6

Взгляните на кампанию Anti-If. Идея состоит не в том, чтобы заменить каждый, если в вашем приложении шаблон стратегии или штата. Идея заключается в том, что когда у вас сложная логика ветвления, особенно на основе чего-то вроде перечисления, вы должны посмотреть на рефакторинг на шаблон стратегии.

И в этом случае вы можете удалить все вместе, используя Factory. Вот относительно простой пример. Конечно, как я сказал в реальном случае, логика в ваших стратегиях будет немного сложнее, чем просто распечатать "Я активен".

public enum WorkflowState
{
  Ready,
  Active,
  Complete
}

public interface IWorkflowStrategy
{
  void Execute();
}

public class ActiveWorkflowStrategy:IWorkflowStrategy
{
  public void Execute()
  {
    Console.WriteLine("The Workflow is Active");
  }
}

public class ReadyWorkflowStrategy:IWorkflowStrategy
{
  public void Execute()
  {
    Console.WriteLine("The Workflow is Ready");
  }
}

public class CompleteWorkflowStrategy:IWorkflowStrategy
{
  public void Execute()
  {
    Console.WriteLine("The Workflow is Complete");
  }
}

public class WorkflowStrategyFactory
{
  private static Dictionary<WorkflowState, IWorkflowStrategy> _Strategies= 
    new Dictionary<WorkflowState, IWorkflowStrategy>();
  public WorkflowStrategyFactory()
  {
    _Strategies[WorkflowState.Ready]=new ReadyWorkflowStrategy();
    _Strategies[WorkflowState.Active]= new ActiveWorkflowStrategy();
    _Strategies[WorkflowState.Complete = new CompleteWorkflowStrategy();
  }
  public IWorkflowStrategy GetStrategy(WorkflowState state)
  {
    return _Strategies[state];
  }
}

public class Workflow
{
    public Workflow(WorkflowState state)
    {
        CurrentState = state;
    }
    public WorkflowState CurrentState { get; set; }
}

public class WorkflowEngine
{
    static void Main(string[] args)
    {
        var factory = new WorkflowStrategyFactory();
        var workflows =
            new List<Workflow>
                {
                    new Workflow(WorkflowState.Active),
                    new Workflow(WorkflowState.Complete),
                    new Workflow(WorkflowState.Ready)
                };
        foreach (var workflow in workflows)
        {
            factory.GetStrategy(workflow.CurrentState).
                Execute();
        }
    }
}   

Ответ 7

Избегайте утверждения If: Существует много способов, один из которых ниже:

int i=0;
if(i==1)
{
//Statement1
}

if(i==2)
{
//Statement2
}

if(i==3)
{
//Statement3
}

if(i==4)
{
//Statement4
}

Использование словаря и делегирования:

delegate void GetStatement ();

Dictionary<int,GetStatement > valuesDic=new Dictionary<int,GetStatement >();

void GetStatement1()
{
//Statement1
}
void GetStatement2()
{
//Statement2
}
void GetStatement3()
{
//Statement3
}


void GetStatement4()
{
//Statement4
}

void LoadValues()
{
valuesDic.Add(1,GetStatement1);
valuesDic.Add(2,GetStatement2);
valuesDic.Add(3,GetStatement3);
valuesDic.Add(4,GetStatement4);

}

Замена If Statement:

int i=0;
valuesDic[i].Invoke();

Ответ 8

В некотором смысле это может быть хорошей идеей. Swiching в поле типа внутри объекта обычно является плохой идеей, когда вы можете использовать виртуальные функции вместо этого. Но механизм виртуальных функций никоим образом не предназначен для замены теста if() в целом.

Ответ 9

Как вы решаете, какой метод объекта использовать без оператора if?

Ответ 10

Это зависит от того, что сравнивает исходный оператор. Мое правило состоит в том, что если оно switch или if проверяет равенство против перечисления, то это хороший кандидат для отдельного метода. Однако операторы switch и if используются для многих и многих других тестов - нет хорошего способа заменить реляционные операторы (<, >, <=, >=) со специализированными методы и некоторые виды перечислимых тестов работают намного лучше со стандартными утверждениями.

Поэтому вы должны заменить if только в том случае, если они выглядят следующим образом:

if (obj.Name == "foo" || obj.Name == "bar") { obj.DoSomething(); }
else if (obj.Name == "baz") { obj.DoSomethingElse(); }
else { obj.DoDefault(); }

Ответ 11

В ответ на вопрос ifTrue:

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

class Nat {
    def cond = {
        print this;
        return this;
    }
}

class NatLessThan<5:Nat> { // subclass of Nat
    override cond = {
        return 0;
    }
}

x = x.cond();

(продолжение...)

Или, без открытых классов, но допускающих множественные диспетчерские и анонимные классы:

class MyCondFunctor {
    function branch(Nat n) {
        print n;
        return n;
    }

    function branch(n:NatLessThan<5:Nat>) {
        return 0;
    }
}

x = new MyCondFunctor.branch(x);

Или, как и раньше, но с анонимными классами:

x = new {
    function branch(Nat n) {
        print n;
        return n;
    }

    function branch(n:NatLessThan<5:Nat>) {
        return 0;
    }
}.branch(x);

У вас было бы намного легче, если бы вы реорганизовали эту логику, конечно. Помните, что существуют полностью системы типа Turing.

Ответ 12

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

Ответ 13

Assume we have conditional values.

public void testMe(int i){

if(i=1){
somevalue=value1;
}


if(i=2){
 somevalue=value2;
}

if(i=3){
somevalue=value3;
}

}

//**$$$$$you can replace the boring IF blocks with Map.$$$$$**

//============================================================================================ ===============

Same method would look like this:
--------------------------------
public void testMe(int i){

Map<Integer,String> map = new HashMap<Integer,String>();

map.put(1,value1);
map.put(2,value2);
map.put(3,value3);

}
This will avoid the complicated if conditions.

Вы можете использовать решение simliar при использовании шаблонов factory для загрузки классов.

public void loadAnimalsKingdom(String animalKingdomType)
    if(animalKingdomType="bird"){
    Bird b = new Bird();
    }
    if(animalKingdomType="animal"){
    Animal a= new Animal();
    }
    if(animalKingdomType="reptile"){
    Reptile r= new Reptile();
    }
  }

Теперь, используя карту:

   public void loadAnimalsKingdom(String animalKingdomType)
    {
       Map <String,String> map = new HashMap<String,String>();

       map.put("bird","com.animalworld.Bird.Class");
       map.put("animal","com.animalworld.Animal.Class");
       map.put("reptile","com.animalworld.Reptile.Class");

       map.get(animalKingdomType);

***Use class loader to load the classes on demand once you extract the required class from the map.***
}

Как решение? Сделайте большие пальцы. - Vv

Ответ 14

Это интересная идея. Я думаю, что вы теоретически могли бы это сделать, но это было бы огромной болью на языке, специально разработанном для его поддержки. Я, конечно, не вижу причин.

Ответ 15

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

Ответ 16

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

If-statements, безусловно, имеют свое место в объектно-ориентированном дизайне.

Ответ 17

Конечно, какая-то форма сравнения должна быть сделана независимо от того, что вы делаете? В конце... уверен, что вы можете избежать утверждений, но вы будете генерировать код, который является IDENTICAL для кода, используя оператор if.

Кто-то исправит меня, если я ошибаюсь, но я не могу думать о времени, когда вы могли бы получить любую форму выигрыша, делая это.

Ответ 18

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

Вот пример реализации Python, который я написал в прошлом для детектора фиксированного размера (двухсторонняя очередь). Вместо того, чтобы создавать метод "remove" и иметь внутри него инструкции if, чтобы увидеть, заполнен ли список или нет, вы просто создаете два метода и переназначаете их при необходимости "remove".

В следующем примере приведен список методов "удалить", но, очевидно, существуют также методы "добавить" и т.д.

class StaticDeque(collections.deque):

    def __init__(self, maxSize):

        collections.deque.__init__(self)
        self._maxSize = int(maxSize)
        self._setNotFull()

    def _setFull(self):

        self._full = True
        self.remove = self._full_remove

    def _setNotFull(self):

        self._full = False
        self.remove = self._not_full_remove

    def _not_full_remove(self,value):

        collections.deque.remove(self,value)

    def _full_remove(self,value):

        collections.deque.remove(self,value)
        if len(self) != self._maxSize and self._full:
            self._setNotFull()

В большинстве случаев это не так полезно, но иногда это может быть полезно.

Ответ 19

Я скажу, что ответ неопределенно да-иш. Особенно, когда язык позволяет выполнять некоторые сложные функциональные программирования (например, С#, F #, OCaml).

Компонент, содержащий 2 оператора, сильно связывает два бизнес-правила, поэтому разложите его.

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

Ответ 20

If-statements довольно явны для программирования, поэтому, короче говоря, вы не можете разумно избегать их.

Однако ключевая цель ООП - фактически, один из "столпов" - это инкапсуляция. Старое правило "инкапсулировать то, что меняется" помогает удалить эти неприятные операторы if и case, когда вы пытаетесь учесть все параметры вашего объекта. Лучшим решением для работы с веткими, специальными случаями и т.д. Является использование чего-то вроде шаблона дизайна "Factory" (Аннотация Factory или Factory Метод - в зависимости от потребностей, конечно).

Например, вместо того, чтобы ваш основной цикл кода проверял, какая операционная система, используемая вами с операторами if, переходите для создания окон графического интерфейса с различными параметрами для каждой ОС, ваш основной код создаст объект из factory, который использует OS, чтобы определить, какой конкретный конкретный объект для конкретной ОС. При этом вы принимаете вариации (и длинные предложения if-then-else) из вашего основного цикла кода и позволяете дочерним объектам обрабатывать его - так что в следующий раз вам нужно внести изменения, такие как поддержка новой ОС, вы просто добавляете новый класс из интерфейса Factory.

Ответ 21

В последнее время я слежу за разговорами о борьбе с другими, и это звучит как экстремальная/гиперболическая риторика для меня. Однако я думаю, что в этом утверждении есть истина: часто логика выражения if может быть более правильно реализована посредством полиморфизма. Я думаю, что хорошо помнить об этом каждый раз, когда вы делаете правильное утверждение if. При этом я думаю, что оператор if по-прежнему является основной логической структурой, и его не следует опасаться или избегать как принцип.

Ответ 22

Мои два бита из того, что я понимаю в объектно-ориентированном подходе -

Во-первых, какие объекты в программе должны быть интуитивными. То есть, я не должен пытаться создать класс "Арифметика" для предоставления математических функций. Это злоупотребление OOD.

Во-вторых, и это очень мое мнение. Его нельзя называть объектно-ориентированным дизайном, но Object и ориентированным на дизайн дизайном! Если имена методов объектов сами по себе не являются интуитивными, тогда унаследованные объекты могут в конечном итоге переопределить уже доступные методы.

Объектно-ориентированный подход, по моему мнению, не является заменой процедурного подхода. Скорее это в основном по двум основным причинам для создателей языка -

  • Лучшая возможность определения переменных.

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

Ответ 23

Я согласен с Вансом в том, что IF не хорош, потому что он увеличивает условную сложность и следует избегать, насколько это возможно.

Полиморфизм является вполне жизнеспособным решением при условии, что он имеет смысл, а не "Избегать If".

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

Ответ 24

Вы должны понять, что (x > 5) действительно означает. Предполагая, что x представляет число, тогда он в основном "классифицирует" все числа, превышающие пять. Таким образом, код будет выглядеть так на языке с синтаксисом python:

class Number(Object):

    # ... Number implementation code ... #

    def doSomething():
        self = 0
        return self

    def doSomethingElse():
        pass

class GreaterThan5(Number):
    def doSomething():
        print "I am " + self

    def doSomethingElse():
        print "I like turtles!"

Затем мы могли бы запустить код следующим образом:

>>> type(3)
<class Number>
>>> type(3+3)
<class GreaterThan5>
>>> 3.doSomething()
0
>>> (3 + 3).doSomething()
I am 6
>>> (7 - 3).doSomethingElse()
>>>

Важное значение имеет автоматическое преобразование типов. Насколько мне известно, ни один из языков сегодня не позволяет вам так много общаться с целыми числами.

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