使用枚举进行Java方法重构

使用枚举进行Java方法重构,java,Java,下面的getCategory方法看起来非常冗余,我想知道是否有人对重构它提出了一些建议,以便使用枚举使它更干净。根据传入的“val”,我需要getCategory从Category类返回正确的Category实例。Category类是由JNI代码生成的,所以我不想更改它。有人有什么想法吗 要重构的方法: private Category getCategory(String val) throws Exception{ Category category; if

下面的getCategory方法看起来非常冗余,我想知道是否有人对重构它提出了一些建议,以便使用枚举使它更干净。根据传入的“val”,我需要getCategory从Category类返回正确的Category实例。Category类是由JNI代码生成的,所以我不想更改它。有人有什么想法吗

要重构的方法:

private Category getCategory(String val) throws Exception{
        Category category;
        if (val.equalsIgnoreCase("producer")) {
            usageCategory = Category.CATEGORY_PRODUCER;
        } else if (val.equalsIgnoreCase("meter")) {
            usageCategory = Category.CATEGORY_METER;
        } else if (val.equalsIgnoreCase("consumer")) {
            usageCategory = Category.CATEGORY_CONSUMER;
        } else {
            throw new Exception("Invalid value: " + val);
        }       
        return usageCategory;
    }
public final class Category {
  public final static Category CATEGORY_PRODUCER = new Category("CATEGORY_PRODUCER", SampleJNI.CATEGORY_PRODUCER_get());
  public final static Category CATEGORY_METER = new Category("CATEGORY_METER", SampleJNI.CATEGORY_METER_get());
  public final static Category CATEGORY_CONSUMER = new Category("CATEGORY_CONSUMER", SampleJNI.CATEGORY_CONSUMER_get());

}
Category.java:生成的JNI(无法更改):

private Category getCategory(String val) throws Exception{
        Category category;
        if (val.equalsIgnoreCase("producer")) {
            usageCategory = Category.CATEGORY_PRODUCER;
        } else if (val.equalsIgnoreCase("meter")) {
            usageCategory = Category.CATEGORY_METER;
        } else if (val.equalsIgnoreCase("consumer")) {
            usageCategory = Category.CATEGORY_CONSUMER;
        } else {
            throw new Exception("Invalid value: " + val);
        }       
        return usageCategory;
    }
public final class Category {
  public final static Category CATEGORY_PRODUCER = new Category("CATEGORY_PRODUCER", SampleJNI.CATEGORY_PRODUCER_get());
  public final static Category CATEGORY_METER = new Category("CATEGORY_METER", SampleJNI.CATEGORY_METER_get());
  public final static Category CATEGORY_CONSUMER = new Category("CATEGORY_CONSUMER", SampleJNI.CATEGORY_CONSUMER_get());

}

您的方法本质上是从预定的
字符串
映射到
类别
,因此为什么不使用
映射
?具体来说,我推荐番石榴,因为这些映射是静态的:

private static final ImmutableMap<String, Category> CATEGORIES_BY_STRING =
        ImmutableMap.of(
            "producer", Category.CATEGORY_PRODUCER,
            "meter", Category. CATEGORY_METER,
            "consumer", Category.CATEGORY_CONSUMER
        );

关于使用枚举:

private Category getCategory(String val) throws Exception{
        Category category;
        if (val.equalsIgnoreCase("producer")) {
            usageCategory = Category.CATEGORY_PRODUCER;
        } else if (val.equalsIgnoreCase("meter")) {
            usageCategory = Category.CATEGORY_METER;
        } else if (val.equalsIgnoreCase("consumer")) {
            usageCategory = Category.CATEGORY_CONSUMER;
        } else {
            throw new Exception("Invalid value: " + val);
        }       
        return usageCategory;
    }
public final class Category {
  public final static Category CATEGORY_PRODUCER = new Category("CATEGORY_PRODUCER", SampleJNI.CATEGORY_PRODUCER_get());
  public final static Category CATEGORY_METER = new Category("CATEGORY_METER", SampleJNI.CATEGORY_METER_get());
  public final static Category CATEGORY_CONSUMER = new Category("CATEGORY_CONSUMER", SampleJNI.CATEGORY_CONSUMER_get());

}
如果您可以完全控制传递到
getCategory
字符串,并且只传递文本值,那么切换到
enum
是有意义的


编辑:之前,我建议在这种情况下使用,但更有意义。

如果您说要基于enum重构,我假设您的意思是不再希望将字符串传递给getCategory来完成所有这些工作。代码直接使用枚举,而不是使用字符串

如果是这种情况,请继续阅读

幸运的是,您的类别是静态变量,因此您可以直接做一些真正的事情

public enum FooCategory {  // give a better name yourself
  PRODUCER(Category.CATEGORY_PRODUCER),
  METER(Category.CATEGORY_METER),
  CONSUMER(Category.CATEGORY_CONSUMER)

  private Category category;
  FooCategory(Category category) {
    this.category=category;
  }
  Category getCategory() {
    return this.category;
  }
}
在旧代码中,您正在执行以下操作:

String fooCategory = "producer";
//....
Category category = getCategory(fooCategory);
// work on category
现在你正在做一些更整洁的事情

FooCategory fooCategory = FooCategory.PRODUCER;
//...
Category category = fooCategory.getCategory();
// work on category

@PaulBellora和@AdrianShum的答案都很好,但我认为出于存储原因,您不能避免使用像“生产者”(不区分大小写)这样的神奇值来生成
类别。因此,
getCategory
中的冗余代码恐怕也无法避免。(不幸的是,用于初始化
Category
和获取
Category
的魔法值不同)

以下是要使用的代码
Enum
(Java 1.5或更高版本):

如果您使用相同的魔法值生成、获取和存储,您可以:

public enum Category {
    CATEGORY_PRODUCER("producer"),
    CATEGORY_METER("meter"),
    CATEGORY_CONSUMER("consumer");

    private String category;
    private Category(String category) {
        this.category = category;
    }

    public static Category of(String val) throws Exception {
        Category usageCategory;
        // You can use equals not equalsIgnoreCase, so you can use map to avoid redundant code.
        // Because you use the same magic value everywhere.
        if (val.equals("producer")) {
            usageCategory = Category.CATEGORY_PRODUCER;
        } else if (val.equals("meter")) {
            usageCategory = Category.CATEGORY_METER;
        } else if (val.equals("consumer")) {
            usageCategory = Category.CATEGORY_CONSUMER;
        } else {
            throw new Exception("Invalid value: " + val);
        }       
        return usageCategory;
    }
}
并创建一个
类别
,如下所示:

Category category = Category.of("producer");

当然,您必须更改代码以包含
SampleJNI。CATEGORY\u CONSUMER\u get()

getCategory
不区分大小写。上面使用的
ImmutableMap
解决了这个问题吗?@Paul Bellora-我喜欢你的建议,但我正在寻找一个使用java 1.6的解决方案。我相信我必须添加另一个库来实现这一点,对吗?@DavidHarkness-当然,你是对的-因此仍然需要该方法,请参阅我的编辑。@DavidHarkness使getCategory()总是在CATEGORIES_之前按_STRING将输入值小写。get()应该没有问题。我想,你的方法现在非常干净,这是一个简单的工厂方法。除非您在许多其他类中需要这样的方法,否则我不建议您花费时间来改进此方法。+1这实际上比我关于使用枚举的回答更有意义。@Adrian Shum-我仍然需要根据传递的字符串(即“生产者”、“消费者”等)做出决定。所以,如果我读对了你的答案,我仍然会有if(val.equalsIgnoreCase(“producer”)切换逻辑,对吗?@c12-如果可能,绝对建议使用枚举而不是字符串文字-但是如果您被迫根据传递的
string
进行决策,则需要坚持使用
Map
解决方案。@c12-正如PaulBellora所建议的,您应该避免使用字符串文字。如果出于某种原因,您仍然eed,除了最理想的映射解决方案外,您还有另一种选择:在FooCategory中添加一个成员变量来存储字符串表示,并迭代foocatery.values()来进行字符串比较。仅当枚举的值最小(我会说低于5)时才使用它@AdrianShum-为了确保我理解,我有很多IF语句,它们测试驱动我在其他代码点的业务逻辑的特定值,例如IF(val.equalsIgnoreCase(“abc”){dothis();}或者IF{val.equalsIgnoreCase(“def”){dosomethingelse();}……等等。我应该为“abc”、“def”使用枚举。这对性能有影响吗?