избегая, если заявления - PullRequest
       53

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

36 голосов
/ 27 августа 2009

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

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

EDIT

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

ВТОРОЕ РЕДАКТИРОВАНИЕ

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

Ответы [ 24 ]

36 голосов
/ 29 мая 2011

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

12 голосов
/ 27 августа 2009

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

if ( x < 5 ) {
   x = 0
} else {
   print x;
}
9 голосов
/ 27 августа 2009

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

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

8 голосов
/ 27 августа 2009

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

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

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

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

6 голосов
/ 27 августа 2009

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

5 голосов
/ 15 апреля 2012

Как избежать утверждения: Есть много способов сделать, один из них ниже:

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:

int i=0;
valuesDic[i].Invoke();
5 голосов
/ 27 августа 2009

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

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

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();
        }
    }
}   
4 голосов
/ 27 августа 2009

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

3 голосов
/ 27 августа 2009

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

3 голосов
/ 27 августа 2009

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

Таким образом, вы должны заменить if s, только если они выглядят так:

if (obj.Name == "foo" || obj.Name == "bar") { obj.DoSomething(); }
else if (obj.Name == "baz") { obj.DoSomethingElse(); }
else { obj.DoDefault(); }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...