сделайте это, еще не используя “если” | если (s == “value1”) {…} если (s == “value2”) {…}

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

if(s == "foo")
{
    Writeln("some logic here");
}
else if(s == "bar")
{
    Writeln("something else here");
}
else if(s == "raboof")
{
    Writeln("of course I need more than just Writeln");
}

(язык: Java или C#)

22
задан JasonMArcher 9 June 2015 в 18:48
поделиться

17 ответов

Воспользуйтесь шаблоном стратегии .

В терминах Java:

public interface Strategy {
    void execute();
}

public class SomeStrategy implements Strategy {
    public void execute() {
        System.out.println("Some logic.");
    }
}

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

Map<String, Strategy> strategies = new HashMap<String, Strategy>();
strategies.put("strategyName1", new SomeStrategy1());
strategies.put("strategyName2", new SomeStrategy2());
strategies.put("strategyName3", new SomeStrategy3());

// ...

strategies.get(s).execute();
17
ответ дан 29 November 2019 в 03:15
поделиться

Сделать ассоциативную структуру данных. Карта на Java, ID словарь на C#. Инициализируйте его в начале времени, а затем ...

.
18
ответ дан 29 November 2019 в 03:15
поделиться

Вот один способ... :)

delegate void DoStuff();

...

IDictionary<string, DoStuff> dict = new Dictionary<string, DoStuff>();
dict["foo"] = delegate { Console.WriteLine("some logic here"); };
dict["bar"] = delegate { Console.WriteLine("something else here"); };
dict["raboof"] = delegate { Console.WriteLine("of course I need more than just Writeln"); };
dict["foo"]();
65
ответ дан 29 November 2019 в 03:15
поделиться

Here goes mine. Используя LINQ и заводскую схему :D

class FactoryString
    {
    static FactoryString()
    {
    private static Dictionary<string, string> dictionary = new Dictionary<string, string> 
    { 
        {"foo", "some logic here"},
        {"bar", "something else here"},
        {"raboof", "of course I need more than just Writeln"},
    };
}

public static string getString(string s)
{
    return dictionary.Single(x => x.Key.Equals(s)).Value;
}

}

static void main()
{
  Console.WriteLine(FactoryString.getString("foo"));
}
0
ответ дан 29 November 2019 в 03:15
поделиться

Я читал http://www.antiifcampaign.com/articles/the-simplest-anti-if-code.html и думаю, что лекарство хуже, чем болезнь. Намного, намного хуже. Чтобы решить возможную (невероятную?) будущую проблему, вам пришлось вложить деньги в тяжелую технику.

.
1
ответ дан 29 November 2019 в 03:15
поделиться

Злоупотребление тернарным оператором, по крайней мере, на C#:

Action result = 
            s == "bar" ? (Action)(() => { Console.WriteLine("bar"); }): 
            s == "foo" ? (Action)(() => { Console.WriteLine("foo"); }) :
                         (Action)(() => { Console.WriteLine(); });

Вообще-то, беру свои слова обратно... никогда НИКОГДА так не делай. Используйте переключатель.

1
ответ дан 29 November 2019 в 03:15
поделиться

Я думаю, что вы ищете Заводские образцы.

3
ответ дан 29 November 2019 в 03:15
поделиться

Можно предположить, что вы можете сделать что-то похожее на вышеприведенный шаблон "стратегии", используя вместо этого карту вызовов методов:

public class FooOrBar {
private Map<String, Method> methodMap = new HashMap<String, Method>();

public FooOrBar() {
    try {
        methodMap.put("foo", this.getClass().getMethod("doFoo", new Class[0]));
        methodMap.put("bar", this.getClass().getMethod("doBar", new Class[0]));
    } catch (NoSuchMethodException n) {
        throw new RuntimeException(n);
    }
}

public void doSomething(String str) {
    Method m = methodMap.get(str);
    try {
        m.invoke(this, null);
    } catch (Exception n) {
        throw new RuntimeException(n);
    }

}

public void doFoo() {
    System.out.println("foo");
}

public void doBar() {
    System.out.println("bar");
}

public static void main(String[] args) {
    FooOrBar fb = new FooOrBar();
    fb.doSomething("foo");

}

}

.
1
ответ дан 29 November 2019 в 03:15
поделиться

Не думаю, что вы делаете здесь справедливое сравнение.

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

Однако в вашем случае из всех приведенных выше примеров видно, что если не удалить с поверхности, то она всегда будет существовать где-то внизу, в центре.

И почему именно это?

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

.
3
ответ дан 29 November 2019 в 03:15
поделиться

Прежде всего, будьте очень внимательны при чтении подобных "анти" кампаний.

  • Спросите себя, хотела бы Анти-кампания IF устранить логику в приложениях?!
  • Идеи могут иметь хорошее применение в одной ситуации и глупость в другой . Будьте разумны.
  • Возможно, что множественное использование IF может обременять читателя кода. но это любая причина для исключения , если из вашего кода, более того, это почти невозможно.
  • Кстати, нигде в руководстве по проектированию РС не рекомендуется использовать , если (как сделано, например, для goto утверждение, что использование ведьмы не рекомендуется)...

C#

    switch (myStringVar)
    {
        case "one": doSomething();  break;
        case "two": doSomething(); break;
        case "three": doSomething(); break;
        default: doSomething(); break;
    }

Наконец, этот код сводится к , если s... так что только для удобочитаемости лучше, а не для производительности.

На самом деле, если Microsoft считает, что переключатель (в c#) лучше заменить на if - OK, я использую (в конкретной ситуации, которую вы описали) переключатель .

Кстати, похоже, что кампания очень четко ответила на ваш вопрос в этом примере

5
ответ дан 29 November 2019 в 03:15
поделиться

Java

Используйте перечисление, которое реализует определенный метод.

enum MyEnum{

    foo{
        public void mymethod(String param1, String param2){
            //dostuff...
        }
    },

    bar{
        public void mymethod(String param1, String param2){
            //dostuff...
        }
    };

    public abstract void mymethod(String param1, String param2);
}

Затем в вашем классе :

MyEnum.valueOf(mystring).mymethod(param1, param2);
7
ответ дан 29 November 2019 в 03:15
поделиться

В одних случаях может быть законным избегать if структуры

в других просто идиотизм, которого следует избегать if.

В то время как приведенные примеры, чтобы избежать if структуры, являются действительными альтернативами, вы должны спросить себя:

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

.
7
ответ дан 29 November 2019 в 03:15
поделиться

пишите классы с виртуальными методами, которые являются производными от вашего абстрактного базового класса SomeThingWriter.

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

abstract class MyBaseClass
{
     public abstract void writeSomething();
}

class DerivedClass1 : MyBaseClass
{
    public override void writeSomething()
    {
        Writeln("something else here  1");
    }
}

class DerivedClass2 : MyBaseClass
{
    public override void writeSomething()
    {
        Writeln("something else here  2");
    }
}

чем просто вызвать типа

MyBaseClass c = new DeriveClass1();
c.writeSomething();
c = new DerivedClass2();
c.writeSomething();
12
ответ дан 29 November 2019 в 03:15
поделиться

Глядя на кампанию, она очень плохо объяснена. Нет ничего плохого в ifs, но в некоторых случаях могут указывать на то, что ООП не используется в полной мере.

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

Вы бы использовали более умный объект вместо того, чтобы быть строкой:

interface I {
  public String getName();
  public void doSomething();
}

class A implements I {
  public String getName() { return "one"; }
  public void doSomething() { ...; }
}

class B implements I {
  public String getName() { return "two"; }
  public void doSomething() { ...; }
}

Тогда вы можете заменить ifs на:

I obj = ...get an A or B from somewhere...;
obj.doSomething();
12
ответ дан 29 November 2019 в 03:15
поделиться
[

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

]. [

] Вот нетривиальный пример из кода производства. На первый взгляд он может показаться немного сложным, но по своей сути он действительно прост: в зависимости от кода расположения на строке заряда, нам необходимо выполнить обновление некоторых из связанных с ним строк предложений. Но мы выбираем разные строки предложений и выполняем на них различного рода обновления для разных кодов расположения.[

]. [

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

]. [

] Стоит подчеркнуть, что написать юнит-тест, покрывающий 100% этого кода, довольно просто. Стоит также подчеркнуть, что сложность этого кода масштабируется линейно по количеству поддерживаемых им кодов диспозиции, предикативно и актуализировано; если бы использовались операторы или регистры, то масштабирование происходило бы экспоненциально[

]. [
    /// <summary>
    /// Update a sentence's status to Completed [401110]
    /// </summary>
    /// <param name="senRow"></param>
    /// <param name="eventDate"></param>
    private static void CompleteSentence(DataRow senRow, DateTime eventDate)
    {
        senRow.SetField("SenStatus", "401110");
        senRow.SetField("SenStatusDate", eventDate);
    }

    /// <summary>
    /// Update a sentence's status to Terminated [401120]
    /// </summary>
    /// <param name="senRow"></param>
    /// <param name="eventDate"></param>
    private static void TerminateSentence(DataRow senRow, DateTime eventDate)
    {
        senRow.SetField("SenStatus", "401120");
        senRow.SetField("SenStatusDate", eventDate);
    }

    /// <summary>
    /// Returns true if a sentence is a DEJ sentence.
    /// </summary>
    /// <param name="senRow"></param>
    /// <returns></returns>
    private static bool DEJSentence(DataRow senRow)
    {
        return Api.ParseCode(senRow.Field<string>("SenType")) == "431320";
    }


    /// <summary>
    /// Returns true if a sentence is a Diversion sentence.
    /// </summary>
    /// <param name="senRow"></param>
    /// <returns></returns>
    private static bool DiversionSentence(DataRow senRow)
    {
        return Api.ParseCode(senRow.Field<string>("SenType")).StartsWith("43");
    }

    /// <summary>
    /// These are predicates that test a sentence row to see if it should be updated
    /// if it lives under a charge disposed with the specified disposition type.
    /// 
    /// For instance, if the PDDispositionCode is 413320, any DEJ sentence under the
    /// charge should be updated.
    /// </summary>
    private static readonly Dictionary<string, Func<DataRow, bool>> PDSentenceTests = 
        new Dictionary<string, Func<DataRow, bool>>
    {
        {"411610", DiversionSentence},  // diversion successful
        {"413320", DEJSentence},        // DEJ successful
        {"442110", DiversionSentence},  // diversion unsuccessful
        {"442111", DiversionSentence},  // diversion unsuccessful
        {"442112", DiversionSentence},  // diversion unsuccessful
        {"442120", DEJSentence}         // DEJ unsuccessful
    };

    /// <summary>
    /// These are the update actions that are applied to the sentence rows which pass the
    /// sentence test for the specified disposition type.
    /// 
    /// For instance, if the PDDispositionCode is 442110, sentences that pass the sentence
    /// test should be terminated.
    /// </summary>
    private static readonly Dictionary<string, Action<DataRow, DateTime>> PDSentenceUpdates = 
        new Dictionary<string, Action<DataRow, DateTime>>
    {
        {"411610", CompleteSentence},   // diversion successful (completed)
        {"413320", CompleteSentence},   // DEJ successful (completed)
        {"442110", TerminateSentence},  // diversion unsuccessful (terminated)
        {"442111", TerminateSentence},  // diversion unsuccessful (terminated)
        {"442112", TerminateSentence},  // diversion unsuccessful (terminated)
        {"442120", TerminateSentence}   // DEJ unsuccessful (terminated)
    };

    private void PDUpdateSentencesFromNewDisposition()
    {
        foreach (DataRow chargeRow in PDChargeRows
            .Where(x => PDSentenceTests.ContainsKey(x.Field<string>("PDDispositionCode"))))
        {
            string disp = chargeRow.Field<string>("PDDispositionCode");
            foreach (DataRow s in CHGRows[chargeRow]
                .ChildRows("CAS-SUBCRM-CHG-SEN")
                .Where(x => PDSentenceTests[disp](x)))
            {
                PDSentenceUpdates[disp](s, EventDate);
            }
        }
    }
]
0
ответ дан 29 November 2019 в 03:15
поделиться
[

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

] [

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

] [

] если операторы (условные прыжки) все еще будут происходить, будь то в вашем коде или в интерпретаторе. сохранение их лексически близко имеет много преимуществ для чтения и обслуживания, которые теряются из-за чрезмерного использования OO. есть баланс, который должен быть достигнут между локальной и удаленной логикой, но он никогда не должен перерастать в помутнение.[

]. [

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

].
4
ответ дан 29 November 2019 в 03:15
поделиться

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

В книге Фаулера Рефакторинг он обсуждает Замену условия полиморфизмом. Это то, что я рассматриваю как хорошее применение для замены утверждений if/switch (там, где это уместно).

4
ответ дан 29 November 2019 в 03:15
поделиться