2017-01-19 3 views
5

Мне нужно написать логику со многими условиями (до 30 условий) в одном наборе правил со многими условиями if else, и это может закончиться между или после всех условий.Нужны предложения по дизайну для вложенных условий

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

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

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

private Boolean RunCondition(Input input) { 
    Boolean ret=false; 
    //First if 
    if(input.a.equals("v1")){ 
     //Somelogic1(); 
     //Second if 
     if(input.b.equals("v2")) 
      //Third if 
      if(input.c >1) 
       //Fourth if 
       //Somelogic2(); 
       //Go fetch key Z1 from database and see if d matches. 
       if(input.d.equals("Z1"))       
         System.out.println("Passed 1"); 
        // Fourth Else 
        else{ 
         System.out.println("Failed at fourth"); 
        } 

      //Third Else 
      else{ 
       if(input.aa.equals("v2")) 
        System.out.println("Failed at third"); 
       } 
     //Second Else 
     else{ 
      if(input.bb.equals("v2")) 
       System.out.println("Failed at second"); 
      } 
    } 
    //First Else 
    else{ 
     if(input.cc.equals("v2")) 
      System.out.println("Failed aat first"); 
     } 

    return ret; 
} 

public class Input { 
    String a; 
    String b; 
    int c; 
    String d; 
    String e;  
    String aa; 
    String bb; 
    String cc; 
    String dd; 
    String ee; 

} 
+2

Было бы намного проще, если бы вы a) вдавили его разумно, б) использовали 'else if'. –

+0

Речь идет ни о моде, ни о дизайне. Речь идет о написании процедурного кода. –

+0

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

ответ

1

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

Это идеальный кандидат для обработки, используя try/catch/finally блок.

Ваша программа может быть переписана в следующем:

private Boolean RunCondition(Input input) { 
    Boolean ret=false; 
    try { 
     //First if 
     if(!input.a.equals("v1")) { 
      throw new ValidationException("Failed aat first"); 
     } 
     //Somelogic1(); 

     //Second if 
     if(!input.b.equals("v2")) { 
      throw new ValidationException("Failed at second"); 
     } 
     //Somelogic2() 

     //Third if 
     if(input.c<=1) { 
      throw new ValidationException("Failed at third"); 
     } 

     //Fourth if 
     //Somelogic2(); 
     //Go fetch key Z1 from database and see if d matches. 
     if(!input.d.equals("Z1")) { 
      throw new ValidationException("Failed at fourth"); 
     } 
     System.out.println("Passed 1"); 

    } catch (ValidationException e) { 
      System.out.println(e.getMessage()); 
    } 

    return ret; 
} 

Где вы можете определить свой собственный ValidationException (как показано ниже), или вы можете использовать некоторые из существующих стандартных исключения, такие как RuntimeException

class ValidationException extends RuntimeException { 

    public ValidationException(String arg0) { 
     super(arg0); 
     // TODO Auto-generated constructor stub 
    } 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 

} 

Вы можете узнать больше об этом в

https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html

+0

Это интересный вариант. Я не решался использовать Exception, поскольку он будет есть память, но даст ему шанс. – Paresh

+1

Исключения не нужны, и их не следует использовать таким образом. См. [Мой ответ] (http://stackoverflow.com/a/41751365/3788176) за небольшую вариацию, которая намного проще и быстрее. –

+0

Догма состоит в том, что исключения не должны использоваться для контроля потока, и поэтому существуют стилистические причины, по которым это решение не должно приниматься. – scottb

1

Сделать отдельный класс для условия:

package com.foo; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

public class App 
{ 
    static class Condition<T> { 
     final int idx; 
     final T compareValue; 
     public Condition(final int idx, final T compareValue) { 
      this.idx = idx; 
      this.compareValue = compareValue; 
     } 
     boolean satisfies(final T other) { 
      return other.equals(compareValue); 
     } 

     int getIdx() { 
      return idx; 
     } 
    } 
    public static void main(String[] args) 
    { 
     final List<Condition<String>> conditions = new ArrayList<Condition<String>>(); 
     conditions.add(new Condition<String>(1, "v1")); 
     conditions.add(new Condition<String>(2, "v2")); 
     final List<String> inputs = new ArrayList<String>(Arrays.asList("v1", "xyz")); 
     boolean ret = true; 
     for (int i = 0; i < inputs.size(); i++) { 
      if (!conditions.get(i).satisfies(inputs.get(i))) 
      { 
       System.out.println("failed at " + conditions.get(i).getIdx()); 
       ret = false; 
       break; 
      } 
     } 
     System.out.println("ret=" + ret); 
    } 
} 
1

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

public interface IRuleCheck 
{ 
    public RuleCheckResult Check(Input input); 
    public String Name(); 
} 

public class RuleCheckResult 
{ 
    private String _errorMessage; 
    public RuleCheckResult(){}//All Good 
    public RuleCheckResult(String errorMessage) 
    { 
     _errorMessage = errorMessage; 
    } 
    public string ErrorMessage() 
    { 
     return _errorMessage; 
    } 
    public Boolean Passed() 
    { 
     return _errorMessage == null || _errorMessage.isEmpty(); 
    } 

} 

public class CheckOne implements IRuleCheck 
{ 
     public RuleCheckResult Check(Input input) 
     { 
      if (input.d.equals("Z1")) 
      { 
      return new RuleCheckResult();//passed 
      } 
      return new RuleCheckResult("d did not equal z1"); 
     } 
     public String Name(); 
} 

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

for (IRuleCheck check : checkList) 
{ 
    System.out.println("checking: " + check.Name()); 
    RuleCheckResult result = check.Check(input); 
    if(!result.Passed()) 
    { 
     System.out.println("FAILED: " + check.Name()+ " - " + result.ErrorMessage()); 
     //either jump out and return result or add it to failure list to return later. 
    } 
} 

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

1

@leeyuiwah's answer имеет четкую структуру условной логики, но исключения здесь не являются правильным инструментом для работы.

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

Отъезд Эффективная Java 2nd Ed Пункт 57: «Используйте исключения только для исключительных условий» для подробного обсуждения того, почему вы не должны использовать такие исключения.

Более простой вариант, чтобы определить немного вспомогательный метод:

private static boolean printAndReturnFalse(String message) { 
    System.out.println(message); 
    return false; 
} 

Тогда:

if(!input.a.equals("v1")) { 
    return printAndReturnFalse("Failed aat first"); 
} 
// etc. 

, который я думаю, что это проще; и это будет намного быстрее.

Смежные вопросы