Java中的条件分支

时间:2014-02-21 13:47:13

标签: java if-statement switch-statement

我想知道您认为哪一种是更好的设计。假设我们有

/*
* Created 21 Feb 2014
*/


import java.util.Properties;
import java.util.Random;

/**
*
* @author me
*/

enum EventType{
    TRADE, RISK, SHIPPING, MARGIN, STOP_LOSS, TAKE_PROFIT
}

interface Event{
    EventType getType();
    Properties getProperties();
}


class ShippingEvent implements Event{
    public final static String PROPERTY_KEY1 = "property_ke1";
    public final static String PROPERTY_KEY2 = "property_ke2";
    public final static String PROPERTY_KEY3 = "property_ke3";

    @Override
    public EventType getType() {
        return EventType.SHIPPING;
    }

    @Override
    public Properties getProperties() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}


class TradeEvent implements Event{
    public final static String PROPERTY_KEY1 = "property_ke1";
    public final static String PROPERTY_KEY2 = "property_ke2";
    public final static String PROPERTY_KEY3 = "property_ke3";

    @Override
    public EventType getType() {
        return EventType.TRADE;
    }

    @Override
    public Properties getProperties() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

class RiskEvent implements Event{
    public final static String PROPERTY_KEY1 = "property_ke1";
    public final static String PROPERTY_KEY2 = "property_ke2";
    public final static String PROPERTY_KEY3 = "property_ke3";

    @Override
    public EventType getType() {
        return EventType.RISK;
    }

    @Override
    public Properties getProperties() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

class MarginEvent implements Event{
    public final static String PROPERTY_KEY1 = "property_ke1";
    public final static String PROPERTY_KEY2 = "property_ke2";
    public final static String PROPERTY_KEY3 = "property_ke3";

    @Override
    public EventType getType() {
        return EventType.MARGIN;
    }

    @Override
    public Properties getProperties() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

class StopLossEvent implements Event{
    public final static String PROPERTY_KEY1 = "property_ke1";
    public final static String PROPERTY_KEY2 = "property_ke2";
    public final static String PROPERTY_KEY3 = "property_ke3";

    @Override
    public EventType getType() {
        return EventType.STOP_LOSS;
    }

    @Override
    public Properties getProperties() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

class TakeProfiEvent implements Event{
    public final static String PROPERTY_KEY1 = "property_ke1";
    public final static String PROPERTY_KEY2 = "property_ke2";
    public final static String PROPERTY_KEY3 = "property_ke3";

    @Override
    public EventType getType() {
        return EventType.TAKE_PROFIT;
    }

    @Override
    public Properties getProperties() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

public class InstanceOfTest {

    private static void testIfBranch(final Event event){
        if (event instanceof TakeProfiEvent){
            System.out.println("TakeProfiEvent");
        }else if (event instanceof StopLossEvent){
            System.out.println("StopLossEvent");
        }else if (event instanceof MarginEvent){
            System.out.println("MarginEvent");
        }else if (event instanceof RiskEvent){
            System.out.println("RiskEvent");
        }else if (event instanceof TradeEvent){
            System.out.println("TradeEvent");
        }else if (event instanceof ShippingEvent){
            System.out.println("ShippingEvent");
        }
    }




    private static void testSwitchBranch(final Event event){

        switch(event.getType()){
            case TRADE:
                System.out.println("TradeEvent");
                break;
            case RISK:
                System.out.println("RiskEvent");
                break;
            case SHIPPING:
                System.out.println("ShippingEvent");
                break;
            case MARGIN:
                System.out.println("MarginEvent");
                break;
            case STOP_LOSS:
                System.out.println("StopLossEvent");
                break;
            case TAKE_PROFIT:
                System.out.println("TakeProfiEvent");    
                break;
            default:
                break;
        }
    }

    public static void main(String[] args){
        Event[] events = new Event[] {
            new TakeProfiEvent(),
            new StopLossEvent(),
            new MarginEvent(),
            new RiskEvent(),
            new TradeEvent(),
            new ShippingEvent()
        };


        Random random = new Random(System.currentTimeMillis());
        long start = System.currentTimeMillis();
        for(int idx=0; idx<10000000; ++idx){
            int jdx = random.nextInt(events.length-1);
            //testIfBranch(events[jdx]);
            testSwitchBranch(events[jdx]);
        }
        long end = System.currentTimeMillis();

        System.out.println("Time taken: " + (end - start));
    }

}

我执行的测试表明,根据Compiling switch in the JVM,switch语句对所有测试用例的表现都更好。此外,我倾向于不使用instanceof运算符,因为我发现在这种情况下,它使得扩展软件变得困难。例如,我使用getType()方法,我可以轻松使用IoC或DI。另外我认为使用instanceof运算符会创建对类定义的明确依赖。我想听听你对此的看法,特别是在软件工程方面 - 陷阱和/或最佳实践。

示例结果:

Switch Branch: 304916ms
If Branch: 307924ms

3 个答案:

答案 0 :(得分:2)

从剥离的示例中我可以看出,这两种方法在软件工程方面都不是真正可扩展且易于维护的。

重要的问题是:您在真正的应用程序中对这些事件(及其类型)做了什么?那就是:查询类型真的必要吗?

在这种情况下,您至少应该考虑的一般模式是通过某种多态来隐藏类型查询。以过于暗示的形式指出:

interface Event{
    void performAction();
    Properties getProperties();
}

class ShippingEvent implements Event{
    @Override
    public void performAction() {
        // Whatever you would otherwise do based on the event type:
        System.out.println("ShippingEvent");
    }
    ....
}


private static void testPolymorphism(final Event event){ 
    event.performAction(); // That's it. No type queries here.
}

但是,从您发布的代码中是否(以及如何)这适用于您的情况很难说明......

答案 1 :(得分:2)

最好的设计毫无疑问是开关之一。有关最佳做法,请参阅 http://www.javapractices.com/topic/TopicAction.do?Id=31

答案 2 :(得分:0)

在这种情况下,性能参数与if与switch没有多大关系,因为你在做不同的事情。你的if是测试一个类是否属于某种类型,而你的开关正在检查枚举是否相等。

此外,在设计方面,您提供的信息非常少,因此很难对可能更好的内容做出任何判断。如果您提供了一些关于为什么要制作这些条件语句以及您希望在每个分支上做什么的信息,那么使讨论更好的第一步就是好。

就最佳实践而言,您希望避免使用if / else构造或switch语句,并根据具体情况采用多态等解决方案。