在工作中我们对代码进行了同行评审,我发现了一些我不喜欢的东西,我想问一下这个特定问题的最佳实践。
我们有一个界面:
public interface Item {
public String getType();
//some other methods
}
和实施班:
public class EmailItem implements Item {
public static final String TYPE = "email";
@Override
public String getType() {
return TYPE;
}
}
以及使用这些类的一些代码:
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());
}
}
此时我们只有一个实现类,因此不需要检查类型,但我们将添加一些其他实现,然后它会有意义(尽管将使用switch
)。
主要问题是EmailItem
将变量TYPE
设置为公共,此变量也有一个getter。
该类的类和实例都应该可以访问这个变量,但是让它public static final
并直接用实例访问它并不是正确/最佳实践(尽管技术上可行)并且何时它将是私有的(因为它应该)然后它不能从其他类访问(其中for
循环是静态的,并且静态在那时没有意义)。
通过讨论,我们提出了使用instanceOf(...)
或instance.getClass().getName()
和EmailItem.class.getName()
的解决方案,但对我来说似乎都不优雅:)。
最后,我的问题是所描述问题最优雅的解决方案是什么?
嘿,这是我在这里的第一个问题,我希望你对它有意义;)。答案 0 :(得分:3)
从OO的角度考虑它我会考虑以下方法:
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();
}
答案 1 :(得分:1)
如果你想这样做,你做的方式很好:
static final
变量TYPE
可让您将其视为类型常量但是,当您发现自己调度由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);
}
}
}
答案 2 :(得分:1)
如果所有"类型"如果你的Item
在编译时已知,你可以使用这样的枚举:
public interface Item {
enum ItemType { MAIL, OTHER; }
public ItemType getType();
//some other methods
}