【问题标题】:Converting many 'if else' statements to a cleaner approach [duplicate]将许多“if else”语句转换为更简洁的方法[重复]
【发布时间】:2013-01-03 10:10:07
【问题描述】:

我这里的代码检测mimeType是否等于某个MIME类型,如果是,它会做一定的转换

public void convertToMp3(File src, File target,String mimeType){
    if(mimeType.equals("audio/mpeg")){
        ...
    }else if(mimeType.equals("audio/wav")){
        mp3ToWav();
    }else if(mimeType.equals("audio/ogg")){
        ...
    }else if(...){
    ... //More if and else here
}

我已经缩短了我的代码,因为它有很多else if语句,什么设计模式适合去除很多if和else 还是 else if 语句?

【问题讨论】:

  • 枚举和开关怎么样?
  • 工厂设计模式不适合你的需求?
  • @RomanC 为什么我要使用工厂设计模式?
  • 您想简化代码,删除许多 if-else 语句,我使用了工厂模式。允许多态性为您工作。
  • if/else 语句有问题吗?当然,它不是一个漂亮的、过度设计的 OOP 模式,但它很简单且易于维护。任何人阅读它都可以理解它,那么为什么要尝试将其转换为其他东西呢?

标签: java design-patterns


【解决方案1】:

你可以有一个Converter 接口。然后你可以为每个 Mimetype 创建一个类,例如:

public interface Converter {

    public void convertToMp3();
    public void convertToOgg();

}

public class MpegConverter implements Converter {

    public void convertToMp3() {
        //Code here
    }

    public void convertToOgg() {
        //Code here
    }

}

每个转换器都需要一个这样的类。然后你可以像这样设置地图:

Map<String, Converter> mimeTypeMap = new HashMap<String, Converter>();

mimeTypeMap.put("audio/mpeg", new MpegConverter());

那么你的convertToMp3 方法就变成了这样:

Converter converter = mimeTypeMap.get(mimeType);
converter.convertToMp3();

使用这种方法,您将来可以轻松添加不同的转换器。

所有未经测试,可能无法编译,但你明白了

【讨论】:

  • 但是如果我有不同的转换器而不是 convertToMp3 怎么办?我也有 Ogg 和 Wav 转换器。我觉得有点失落,如果我想添加一个 Ogg 转换器
  • 您可以在接口中添加额外的方法。例如convertToOgg() 我更新了答案
  • 在这个例子中,在 MPEGConverter 上使用 convertToMp3 方法将 MPG 转换为 MP3,convertToOgg 用于从 MPG 转换为 OGG。所以不,他们没有做同样的工作。可能与命名混淆
  • 好主意,对我来说似乎是一个非常干净的解决方案。只是不要忘记检查是否真的有处理程序,如果找不到处理程序,则给出错误消息。
  • 对于那些可能不知道的人,这被称为Strategy Pattern。
【解决方案2】:

如果您使用的是 JDK7 之前的版本,您可以为所有 MIME 类型添加一个枚举:

  public static enum MimeTypes {
      MP3, WAV, OGG
  }

  public class Stuff {
      ...
      switch (MimeTypes.valueOf(mimeType)) {
          case MP3: handleMP3(); break;
          case WAV: handleWAV(); break;
          case OGG: handleOGG(); break;
      }
  }

看看关于如何将字符串转换为枚举的 Stack Overflow 问题Java - Convert String to enum。

【讨论】:

  • 为什么不在枚举本身放置一个句柄方法呢?那么它将是MimeTypes.valueOf(mimeType).handle()。
  • @SpaceTrucker:好建议,它会比我的想法更干净。事实上,这将是一个很好的 cowls 想法的实现,因为不需要处理具有不同实现的 Map
  • 我不敢相信建议使用switch 作为重构多个if else if 的一种方式得到23 个赞成票。 Grrr......当我想到那里有什么样的开发人员时,我感到害怕。
  • @Daniel 好吧,我猜有太多开发人员认为“行数越少 = 越好”,尽管新代码与旧代码相比具有相同的缺点。
  • @Daniel,您能否更明确地表达您对这种方法的担忧?问题中提供的用例归结为“基于输入变量执行一个且只有一个的代码路径”,这(在我看来)是对开关应该做什么的一个很好的定义。
【解决方案3】:

考虑使用策略设计模式和Map 来分派到适当的策略。如果您需要额外的功能,除了特定 mimeType 的转换之外,或者转换器是大而复杂的代码并且您希望将每个转换器放在其自己的 .java 文件中,这将特别有用。

 interface Convertor {
    void convert(File src, File target);
 }

 private static void convertWav(File src, File target) {
    ...
 }

 ...

 private static final Map< String, Convertor > convertors = new ...;
 static {
    convertors.put("audio/wav", new Convertor {
       void convert(File src, File target) {
          convertWav(src, target);
       }
    });
    convertors.put("audio/ogg", new Convertor {
       void convert(File src, File target) {
          convertOgg(src, target);
       }
    });
    ...
 }

 public void convertToMp3(File src, File target, String mimeType){
     final Convertor convertor = convertors.get(mimeType);
     if (convertor == null ) {
        ...
     } else {
        convertor.convert(src, target);
     }
 }

【讨论】:

    【解决方案4】:

    如果您对每个案例运行相同的方法,您应该检查State pattern

    【讨论】:

    • 我运行不同的方法。
    • 这里不需要状态模式,这不是对有限状态机进行建模,而是根据输入类型选择不同的转换策略,因此策略模式更合适。
    【解决方案5】:

    如果你使用JDK 7,你可以使用switch-case构造:

    见:Why can't I switch on a String?

    对于之前的版本,if-else 是唯一的选择。

    【讨论】:

      【解决方案6】:

      这绝对是一种策略设计模式。但是您的总体设计存在很大问题。使用 String 来识别类型并不是一个好的编程习惯。仅仅是因为它很容易编辑,而且你可能会犯语法错误,然后整个下午都在寻找编程错误。您可以避免使用地图。

      我建议如下:

      1. 扩展类文件。新类向 File 类添加了一个新属性 FileType 和一个新方法 convertTo(FileType)。这个属性持有它的类型:“audio”,“wav”......并且再次不要使用字符串,使用枚举。在这种情况下,我将其称为 FileType。随心所欲地扩展文件:WavFile、AudioFile...
      2. 使用策略 dp 创建您的转换器。
      3. 使用 Factory dp 初始化转换器。
      4. 由于每个 File 都知道自己的类型和目标类型(使用 convertTo() 方法指定目标类型),它会调用工厂自动获取正确的转换器!!!

      这种设计是可扩展的,您可以根据需要添加尽可能多的 FileType 和转换器。 您投票的答案具有误导性!!!! 编码和黑客之间有很大的区别。

      【讨论】:

        【解决方案7】:

        如果您不使用 Java 7,您可以创建一个 enum 并将该值与 switch 案例一起使用。然后你只需要传递枚举值(而不是文件,我不知道你为什么这样做)。它看起来也会更整洁。

        这些应该对您想要做的事情有所帮助:

         [Java Enum Examples][1] - 
         [Java Switch Case examples][2]
        

        【讨论】:

          猜你喜欢
          • 2014-12-26
          • 2019-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多