java:一长串条件,怎么办? [关闭]

Posted

技术标签:

【中文标题】java:一长串条件,怎么办? [关闭]【英文标题】:java: A long list of conditions , what to do? [closed] 【发布时间】:2012-12-23 13:57:53 【问题描述】:

我需要有关在 Java 中应用条件的正确方法的建议。

我有 100 个条件,我必须根据这些条件更改将显示给用户的字符串变量的值。

一个示例条件:a<5 && (b>0 && c>8) && d>9 || x!=4

存在更多条件,但变量或多或少是相同的。

我现在正在这样做:

    if(condition1)
    else if(condition2)
    else if(condition3)
    ...

一个 switch case 替代方案显然会嵌套在 if-else 中,即

if(condition1)
 switch(x)
  
   case y:
     blah-blah
           
else if(condition2)
switch(x)
  
   case y:
     blah-blah
     
else if(condition3)
...

但我正在寻找一些更优雅的解决方案,例如使用具有多态支持的接口,我可以做些什么来避免代码行或应该是正确的方法。

---编辑---


我实际上在安卓设备上需要这个。但这里更像是一个 java 构造。

这是我所拥有的条件的一个小快照。如果有几个通过/失败,将添加更多。这显然需要更多带有/不带有嵌套的 if-else。在那种情况下,处理会变慢。

我现在将消息存储在一个单独的类中,其中包含我保持静态的各种字符串变量,因此如果条件为真 然后我从唯一的类中选择静态变量并显示它 一。存储结果消息是否正确。

【问题讨论】:

我不确定避免代码行。但是为了提高性能,将更频繁的案例放在首位? 恕我直言,这个问题更适合codereview.stackexchange.com 性能对您来说有多重要?因为在灵活性和可读性方面,一些更“优雅”的解决方案在 if-elses 的情况下会比丑陋的树表现得更糟糕 在我看来你的条件太多了。我认为您的设计应该改进,请添加一些有关您希望使用该代码完成的高级任务的详细信息 pKs - 然后将任何分类/规则引擎抛出窗口。下面@thkala 建议的查找表是您最好的选择,它实际上可能执行得更快,这取决于您在给定输入数据的情况下生成密钥的速度 【参考方案1】:

根据条件输入的数量,您可以使用查找表,甚至是HashMap,通过将所有输入甚至一些相对简单的复杂条件编码为单个值:

int key = 0;

key |= a?(1):0;
key |= b?(1<<1):0;
key |= (c.size() > 1)?(1<<2):0;
...

String result = table[key]; // Or result = map.get(key);

此范例具有恒定时间 (O(1)) 复杂性的额外优势,这在某些情况下可能很重要。根据条件的复杂性,您甚至可能在代码路径中平均拥有更少的分支,而不是完整的 if-then-else 意大利面条代码,这可能会提高性能。

如果您在问题中添加更多上下文,我们可能会为您提供更多帮助。条件输入来自哪里?它们是什么样的?

还有更重要的问题:What is the actual problem that you are trying to solve?

【讨论】:

我认为这将很难维护,因为您最终会得到一长串语句,其中单个语句本身很复杂。由于这些条件用于用户消息,因此它们可能会经常更改。因此,您将在代码中创建一个维护热点。 @SpaceTrucker:我原则上同意,尽管这取决于代码的实际布局方式以及它的具体用途。很有可能,一旦 OP 让我们知道这到底是怎么回事,我们会找到一个更优雅的解决方案来处理高级任务,而不是试图从本质上回答“一个人如何编写复杂的代码” Java中的逻辑表?” @thkala 很抱歉我的回复晚了,感谢您的建议。我要显示的消息是固定的。但是正如您建议的查找表一样,我将考虑它。但是如果我只是使用 if-elses ,我实际上会在哪里滞后。 @pKs:这取决于......这确实会将字符串与您的代码的其余部分分开,但它确实存在一些模块化问题。你真的想让你的应用程序中的所有类都从那里提取它们的字符串吗?如果我是你,我会先看看 android 应用程序是如何支持国际化的 - 很可能无论如何你都必须这样做,那么为什么不从一开始就做好呢? @assylias:我不知道“很棒”,但在某些情况下它可能是一个不错的选择。至于您对int 的关注,大小无关紧要——您始终可以使用long 甚至BitSet。至于它变得一团糟,合适的编码风格会有很大帮助——例如使用位掩码的常量。【参考方案2】:

这有很多可能性。在不了解您的域的情况下,我会创建类似(您可以想到更好的名称:P)

 public interface UserFriendlyMessageBuilder 
      boolean meetCondition(FooObjectWithArguments args);

      String transform(String rawMessage);
 

通过这种方式,您可以创建 UserFriendlyMessageBuilderSet 并仅遍历它们以获取满足转换原始消息条件的第一个。

public class MessageProcessor 
    private final Set<UserFriendlyMessageBuilder> messageBuilders;

    public MessageProcessor(Set<UserFriendlyMessageBuilder> messageBuilders) 
        this.messageBuilders = messageBuilders;
    

    public String get(FooWithArguments args, String rawMsg) 

        for (UserFriendlyMessageBuilder msgBuilder : messageBuilders) 
            if (msgBuilder.meetCondition(args)) 
                return msgBuilder.transform(rawMsg);
            
        
        return rawMsg;    
    

【讨论】:

这将具有 O(N) 查找时间(N 是此类分类器的数量),而不是 if-else 树的较低复杂度(log(N) 理想地用于树) @radai 我明白你的意思。 ~Log(N) 只有当他的 if/else 嵌套在另一个 if/else 中时才会发生。如果不是,它们也将是相同的 O(N)。此外,我认为对于这种简单比较的情况,所花费的时间会非常少。 @RalfHoppen if-elses 在我的情况下没有嵌套,但这可能是一个选择问题。让我们也标记它以添加关于我是否使用嵌套的天气的建议【参考方案3】:

在我看来,“您对模块式产品设计的重视程度很低” 这是使用OOP语言的主要因素。

例如:如果您有 100 个条件,并且您能够制作 4 个模块,那么理论上任何要选择的模块都需要 26 个条件。

【讨论】:

【参考方案4】:

这是另一种可能值得考虑的可能性。

进行每个比较,计算其真值,然后在真值表中查找得到的 boolean[]。 simplifying truth tables 上有很多现有的工作可以申请。我有一个真值表简化applet我多年前写的。您可能会发现它的源代码很有用。

这样做的代价是进行所有比较,或者至少是使用简化真值表评估表达式所需的比较。优点是管理复杂条件组合的有组织的系统。

即使您不直接在代码中使用真值表,也请考虑将编写和简化作为一种​​组织代码的方式。

【讨论】:

以上是关于java:一长串条件,怎么办? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

str.Format(_T("%lf"),n1),转换的字符串会出现小数点后的一长串零,怎么去掉?

设计带有一长串查询参数的 RESTful 查询 API [关闭]

在Java .replaceAll方法中转义一长串元字符

更新表格以擦除一长串 html

验证一长串随机邮政编码的最佳方法

如何在 VueJS 中将一长串“手表”转换为功能方式?