【问题标题】:Getting rid of if/else while calling similar classes Java在调用类似 Java 的类时摆脱 if/else
【发布时间】:2015-08-12 12:12:40
【问题描述】:

我有一个我想要并且需要摆脱一些 if else 情况的问题。我的项目中有以下代码:

if (ar[4].equals("week")) {

    WeekThreshold wt = new WeekThreshold();
    firstTime = unparsedDate.format(wt.getStartDate().getTime());
    secondTime = unparsedDate.format(wt.getEndDate().getTime());

} else if (ar[4].equals("month")) {

    MonthThreshold mt = new MonthThreshold();
    firstTime = unparsedDate.format(mt.getStartDate().getTime());
    secondTime = unparsedDate.format(mt.getEndDate().getTime());

} else if (ar[4].equals("quarter")) {

    quarterThreshold();

} else if (ar[4].equals("year")) {

    YearThreshold yt = new YearThreshold();
    firstTime = unparsedDate.format(yt.getStartDate().getTime());
    secondTime = unparsedDate.format(yt.getEndDate().getTime());
}

WeekThresholdMonthThresholdYearThreshold 三个类扩展自 AbstractThreshold 类,它们从日历中获取日期,但这并不重要。 quarterThreshold()这个方法比较特殊,可以留在那里。但是,如果 else 阻塞并有一个语句来调用不同的类,我该如何摆脱它呢?

编辑:忘了提一下,需要调用的类来自各种数组ar[]。如果数组ar[4] 是月份,则必须调用MonthThreshold 等。

【问题讨论】:

  • 你考虑过工厂设计模式吗?
  • 这也是我的一位伙伴告诉我的,但我很新鲜,哎呀……我会用谷歌搜索,但当然任何提示都会很好:)跨度>
  • 我会为你编写一些代码...给我一分钟
  • 如果你想摆脱命令式代码(if/else),你需要一个声明式解决方案;使用enum

标签: java if-statement switch-statement


【解决方案1】:

多种可能性... XYZThreshold 类是否具有通用接口,例如 Threshold?然后你可以分配一个变量,例如...

Threshold threshold = null;
if ((ar[4].equals("week")) {
  threshold = new WeekThreshold();
} else ... {

}

firstTime = unparsedDate.format(threshold.getStartDate().getTime());
secondTime = unparsedDate.format(threshold.getEndDate().getTime());

这将是第一步。例如,如果您愿意,可以使用枚举来存储阈值:

enum Thresholds {
  WEEK("week") {

     public Threshold getThreshold() {
           return new WeekThreshold();
     }
  },
  etc.

  private String period;

  private Thresholds(String period) {
    this.period = period;
  }

  public abstract Threshold getThreshold();

  //  ...add a static class to iterate and search by period, 
  // ...so you can write Threshold threshold = Thresholds.getByPeriod("week").getThreshold();
}

使用枚举是个人喜好,当然,您可以对普通类执行相同的操作,或者只需将用于阈值选择的 if 块放入单独的类中。

【讨论】:

  • 他们都使用同一个 AbstractClass,是的
  • 区别取决于您是否每次都想要一个新实例。如果没有,您可以用一个实例构造枚举,true。否则,您需要其他版本 - 或反射。
  • OP 的问题似乎非常适合富有的enum,正如您在此处所描绘的那样。比基于 String / Map 的普通解决方案优雅得多。
【解决方案2】:

您可以像这样在外面合并公共代码(unparsedDate.format(...)):

AbstractThreshold at = null;
switch(ar[4]) {
case "week":
    at = new WeekThreshold();
    break;
case "month":
    at = new MonthThreshold();
    break;
case "year":
    at = new YearThreshold();
    break;
case "quarter":
    quarterThreshold();
    break;
}
if(at != null) {
    firstTime = unparsedDate.format(at.getStartDate().getTime());
    secondTime = unparsedDate.format(at.getEndDate().getTime());
}

当然,过度设计的版本是可能的。这只是一个说明如何使用 Java-8 功能实现它:

// Map can be initialized only once, then used many times
Map<String, Supplier<AbstractThreshold>> thresholdSuppliers = new HashMap<>();
thresholdSuppliers.put("week", WeekThreshold::new);
thresholdSuppliers.put("month", MonthThreshold::new);
thresholdSuppliers.put("year", YearThreshold::new);

AbstractThreshold at = thresholdSuppliers.getOrDefault(ar[4], () -> null).get();
if(at != null) {
    firstTime = unparsedDate.format(at.getStartDate().getTime());
    secondTime = unparsedDate.format(at.getEndDate().getTime());
} else if(ar[4].equals("quarter"))
    quarterThreshold();
}

【讨论】:

  • 遗憾的是不允许使用 switch/case,因为它与 if/else 过于相似
  • @wg15music,谁不允许?
  • 主管,因为这是深入 OOP 的实践
  • @wg15music,添加了一个新版本只是为了迷惑你的主管:-)
【解决方案3】:

在这里你可以充分利用FactoryPattern

class ThresholdFactory
{
  public static AbstractThreshold getThreshold(String criteria)
  {
    if ( criteria.equals("week") )
      return new WeekThreshold();
    if ( criteria.equals("month") )
      return new MonthThreshold();
    if ( criteria.equals("year") )
      return new YearThreshold();

    return null;
  }
}

其余代码如下所示:

AbstractThreshold at = ThresholdFactory.getThreshold(ar[4]);
if(at != null){
  firstTime = unparsedDate.format(at.getStartDate().getTime());
  secondTime = unparsedDate.format(at.getEndDate().getTime());
} else {
   quarterThreshold();
}

【讨论】:

  • 完美运行,谢谢!了解工厂如何工作的好代码:)
  • @wg15music,请注意,您仍然需要删除相同数量的 if-else 语句。他们只是转移到了单独的方法。
  • 但有人告诉我我可以使用工厂模式...我可能可以添加一些枚举或哈希图...但最终我无法完全摆脱这些,对吗?他们必须在某个地方......我会把它展示给我的主管,希望这对他来说已经足够了:)
  • 您可以使用enum 消除ifs。
  • 或使用地图,我知道。但是,是否值得使用样板来摆脱 3 个 if 语句,这是值得商榷的-.- 我会避免我的声明。
【解决方案4】:

首先创建阈值工厂,

static enum ThresholdsFactory {


        week(new WeekThreshold()), month(new MonthThreshold())/* etc */;

        static private Map<String,ThresholdsFactory> lookup = new HashMap<String, ThresholdsFactory>();
        static{
            for(ThresholdsFactory val :  ThresholdsFactory.values()){
            lookup.put(val.name(), val);
            }
        }

        public AbstractThreshold threshold;

        public static ThresholdsFactory find(String name){
            return lookup.get(name);
        }

        ThresholdsFactory(AbstractThreshold th) {
            threshold = th;

} }

现在你需要做的就是

AbstractThreshold th = ThresholdsFactory.find(ar[4]);

if (th!=null){
    firstTime = unparsedDate.format(th.getStartDate().getTime());
    secondTime = unparsedDate.format(th.getEndDate().getTime());
}

【讨论】:

    【解决方案5】:

    这是一个如何使用接口和工厂设计模式的示例 如果您的多个实现者共享公共代码,让他们都扩展一个实现接口的抽象类。通过接口引用您的方法是个好主意,而不是通过具体类来利用多态性...请参阅下面的代码...

    public class Example {
    
        public static void main(String[] args) {
    
            String[] intervals = {"week", "week", "quarter", "month", "year", "week"}; 
    
            IThreshold[] objects = new IThreshold[intervals.length];
    
            // Create your objects using Factory pattern
            for(int index = 0; index < intervals.length; index++) {
                objects[index] = ThresholdFactory.createInstance(intervals[index]);
            }
    
            // Now iterate through your objects and refer to them through a common interface
            for(IThreshold object : objects) {
                int start = object.getFirstTime();
                int end = object.getFirstTime();
            }
        }
    }
    
    interface IThreshold {
        public int getFirstTime();
        public int getLastTime();
    }
    
    
    abstract class AbstractThreshold implements IThreshold {
    
        @Override
        public int getFirstTime() {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public int getLastTime() {
            // TODO Auto-generated method stub
            return 0;
        }
    
    }
    
    class WeekThreshold extends AbstractThreshold {}
    class MonthThreshold extends AbstractThreshold {}
    class QuarterThreshold extends AbstractThreshold {}
    class YearThreshold extends AbstractThreshold {}
    
    class ThresholdFactory {
    
        public static final IThreshold createInstance(String interval) {
            IThreshold instance = null;
    
            if(interval.equals("week")){
                instance = new WeekThreshold();
            } 
            else if(interval.equals("month")){
                instance = new MonthThreshold();
            } 
            else if(interval.equals("quarter")){
                instance = new QuarterThreshold();
            } 
            else {
                if(interval.equals("year")){
                    instance = new YearThreshold();
                }
            }
            return instance;
        }
    }
    

    【讨论】:

      【解决方案6】:

      你可以使用 switch 语句

      String typeOfDay;
           switch (dayOfWeekArg) {
               case "Monday":
                   typeOfDay = "Start of work week";
                   break;
               case "Tuesday":
               case "Wednesday":
               case "Thursday":
                   typeOfDay = "Midweek";
                   break;
               case "Friday":
                   typeOfDay = "End of work week";
                   break;
               case "Saturday":
               case "Sunday":
                   typeOfDay = "Weekend";
                   break;
               default:
                   throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
           }
      

      你可以用你自己的代码替换我从java文档中偷来的例子

      switch(periodType){
          case "week":
            WeekThreshold wt = new WeekThreshold();
          break; // add your other cases
      }
      firstTime = unparsedDate.format(wt.getStartDate().getTime());
      secondTime = unparsedDate.format(wt.getEndDate().getTime());
      

      【讨论】:

      • String-Switches 仅适用于 Java 7+,但这通常不是问题,只是想提一下。
      猜你喜欢
      • 2015-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 2017-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多