Public 带有 getter 的静态最终变量

Public static final variable with getter

在工作中,我们对代码进行了同行评审,我发现了一些我不喜欢的东西,我想询问针对这个特定问题的最佳实践。

我们有一个界面:

public interface Item {
    public String getType();
    //some other methods
}

和一个实现 class:

public class EmailItem implements Item {  
    public static final String TYPE = "email";

    @Override
    public String getType() {
        return TYPE;
    }
} 

和一些使用 classes 的代码:

for (Item item : items) {
    if (EmailItem.TYPE.equals(item.getType())) {
        isProcessed = Processor.process(item);
    } else {
        LOGGER.error("Unknown failover type received to process. Type: {}", item.getType());
    }
}

此时我们只有一个实现 class,因此不需要检查类型,但我们将添加一些其他实现,然后它才有意义(尽管将使用 switch)。

主要问题是 EmailItem 将变量 TYPE 设置为 public 并且此变量还有一个 getter.

class 和那个 class 的实例都应该可以访问这个变量,但是拥有它 public static final 并直接用实例访问它似乎 right/best实践(尽管这在技术上是可行的)并且当它是私有的(它应该)时,它就不能从其他 classes 访问(其中 for 循环是静态的,在那个点)。

通过讨论,我们提出了使用 instanceOf(...)instance.getClass().getName()EmailItem.class.getName() 的解决方案,但其中 none 对我来说似乎很优雅 :).

最后,我的问题是,对于所描述的问题,最优雅的解决方案是什么?

嘿,这是我的第一个问题,我希望它对你有意义 ;)。

从面向对象的角度考虑,我会考虑以下方法:

public interface Item {
    public boolean process();
    //some other methods
}

public class EmailItem implements Item {  
    @Override
    public boolean process() {
        // email specific implementation
    }
}

public class AnotherItem implements Item {  
    @Override
    public boolean process() {
        // another implementation
    }
}

for (Item item : items) {
   isProcessed = item.process();
}

你这样做的方式很好,如果你想这样做的话:

  • static final 变量 TYPE 让你把它当作类型常量,
  • 实例上的实现允许您根据接口上的 return 值检查常量。

但是,当您发现自己在 String 或其他值表示的类型上进行调度时,您通常会走上面向对象代码中 switch 语句的错误路径。如果此时您可以选择操作,请考虑双重分派的替代技术,例如实现 Visitor Pattern:

interface ItemVisitor {
    void visitEmail(EmailItem item);
    void visitSms(SmsItem item);
}
interface Item {
    void accept(ItemVisitor v);
}
class EmailItem implements Item {
    public void accept(ItemVisitor v) { v.visitEmail(this); }
}
class SmsItem implements Item {
    public void accept(ItemVisitor v) { v.visitSms(this); }
}

现在你可以这样做了:

class Example implements ItemVisitor {
    public void visitEmail(EmailItem item) {
        // Do something with an e-mail
    }
    public void visitSms(SmsItem item) {
        // Do something with an SMS
    }
    public static void main(String[] args) {
        Example e = new Example();
        for (Item item : ItemSource.getManyItems()) {
            item.accept(e);
        }
    }
}

如果您的 Item 的所有 "types" 在编译时都是已知的,您可以使用这样的枚举:

public interface Item {
    enum ItemType { MAIL, OTHER; }

    public ItemType getType();
    //some other methods
}