有啥完美的方法替代java中的 if-else,switch-case

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有啥完美的方法替代java中的 if-else,switch-case相关的知识,希望对你有一定的参考价值。

参考技术A

可以利用设计模式中的状态模式,将不同的情况设为不同的条件封装成一个类,然后通过一个总的环境类context去管理,不同的条件给其设定的不同的 方法,最后使用哪个条件就直接调用其对应的状态。这个模式可以很好的消除if-else。

我们来举个例子:

假如酒店的房间有三个状态:已入住,空闲,已预定。那么根据三个不同的状态,你可能写if else就要按照如下的逻辑:

如果采用状态模式:

public interface State 

void handle();



public class BookedState implements State  //预定状态

public void handle() 

System.out.println("The state is booked");





public class FreeState implements State //空闲状态

public void handle() 
System.out.println("The state is Free");



 
public class BookedState implements State  //预定状态

public void handle() 

System.out.println("The state is booked");





public class Context  //环境类,持有接口的一个引用

private State state;

public State getState() 
return state;


public void setState(State state) 

this.state = state;

state.handle();



public class Client   //客户端测试类

public static void main(String[] args) 

Context context = new Context();

context.setState(new FreeState()); //需要哪个直接set哪个的值



由此可见,状态模式里没有任何一句if else,可以很好的消除判断,下面是状态模式的结构图:

带有 instanceof 的 if-else 的 Java 设计替代方案

【中文标题】带有 instanceof 的 if-else 的 Java 设计替代方案【英文标题】:Java design alternatives to if-else with instanceof 【发布时间】:2017-01-19 08:24:58 【问题描述】:

我们的 Java 应用程序在后端使用 Google Guava EventBus 进行通信。其中一些事件使用 Jersey 的 server-sent events support 发送到客户端以启用通知。客户端只对某些类型的事件感兴趣,这些事件以 JSON 格式发送到客户端。

目前我们正在使用if-elseinstanceof 以一种巨大的方法处理JSON 正文生成。 UIEvent 只是一个标记接口,用作过滤器。

@Subscribe
public void handleEvent(final UIEvent event) 
  if (event instanceof A) 
    A a = (A) event;

   else if (event instance B) 
    B b = (B) event;

   ...

当越来越多的事件添加到系统中时,这段代码开始变得混乱。经过一番研究,有一些替代方案,但还不够好。

1) 反思。

使用反射意味着我们可以使用声明的方式从事件对象中检索数据,而无需知道确切的类型。但是使用反射不是类型安全的,并且在处理嵌套路径时可能会很混乱,例如a.b.c.

2) 多态性

多态性看起来是instanceof 的一个很好的替代方案,但在这种情况下确实有效。使用多态意味着将toJSON 之类的方法添加到UIEvent 接口。但这会恢复依赖流并将 UI 细节暴露给事件总线。

3) 包装类

我还在考虑使用事件包装类将 JSON 主体构建逻辑封装在单独的类中。然后在事件总线的handleEvent方法中,我可以得到事件对象的类型并使用命名约定找到封装类,然后构造封装类实例,调用toJson方法得到JSON体。

public class AWrapper 
   public AWrapper(A a) 

   

   public Object toJson() 

   

这是迄今为止我能想到的最合理的方法。

需要建议和想法。

【问题讨论】:

Polymorphism 是这里的标准模式。但是,如果可能的话,您应该尝试在事件中测试一个字段并打开它。 多态性也有我的投票权。但是在接口上使用toJson 之类的方法会锁定您使用 json。您可以考虑的另一个解决方案是添加一个返回一组通用数据属性(例如Map<String, Object>)的方法,然后您可以使用该方法将其序列化为 json。 像 Jackson 或 Gson 这样的现代库可以毫不费力地将 POJO 序列化为 JSON,因此您不需要特殊的方法。为什么不创建一个自定义注释来区分内部事件和需要广播给客户端的事件?然后,您将在 handleEvent() 中使用反射来检查注释是否存在。 @markspace 我不想使用多态的原因是因为事件类在核心模块中,也被其他模块使用,但是对 JSON 逻辑的序列化在 API 模块中。我不想让核心模块知道 API 模块。 @MickMnemonic 发送到客户端的 JSON 正文有预定义的格式,所以简单的 JSON 序列化是不够的,需要进行数据转换。之前没考虑过自定义注解,看起来是区分不同事件的好选择。 【参考方案1】:

我相信Google Guava EventBus 是经过精心设计的,因此您不必使用许多 if-else-if 来定义这样的方法:

有些人为 EventBus 提出了一个通用的 Handler 接口 听众。这会遇到 Java 使用类型擦除的问题,而不是 提到可用性方面的问题。

...

由于擦除,没有一个类可以使用不同的类型参数多次实现泛型接口。这与传统的 Java 事件相比是一个巨大的倒退,即使 actionPerformed 和 keyPressed 不是很有意义的名称,至少您可以实现这两种方法!

通过创建自己的标记,您正在重新创建他们试图避免的问题。

对我来说,这就是 Guava 建议的使用方式:

EventBus eventBus = new EventBus();
eventBus.register(new Object()
    @Subscribe
    public void handleEvent(A a) 
        System.out.println("a");
    
);

eventBus.register(new Object()
    @Subscribe
    public void handleEvent(B b) 
        System.out.println("b");
    
);

...

eventBus.post(new A());
eventBus.post(new B());

每个事件类型一个处理程序方法。 显然,订阅者不需要像本例中那样处于匿名类中

其他示例

http://tomaszdziurko.pl/2012/01/google-guava-eventbus-easy-elegant-publisher-subscriber-cases/

【讨论】:

以上是关于有啥完美的方法替代java中的 if-else,switch-case的主要内容,如果未能解决你的问题,请参考以下文章

有啥完美的方法替代java中的 if-else,switch-case

带有 instanceof 的 if-else 的 Java 设计替代方案

在这种情况下,是不是有比 if-else 更快的替代方法?

JAVA中newinstance方法显示已过时,那么有啥方法作为替代呢?

if-else 和 switch 语句的替代方案

c++ 中的 dynamic_cast 有啥替代方法吗?