【问题标题】:remove conditional statements when dealing with inheritance处理继承时删除条件语句
【发布时间】:2014-04-22 05:55:26
【问题描述】:

我想避免使用条件并应用一些技术来使代码在处理继承的类时更易于维护和扩展。

在这个例子中我们有。

MarketOrder 和 LimitOrder 都从基类 Order 扩展而来。

TradeServiceImpl 使用 getUnitPrice 方法计算 2 个订单将被交易的价格。

此方法有几个条件可以为不同类型的订单选择正确的价格。此外,它正在转换为派生类。

这种方法的问题是,如果我想添加 5 个新订单,我将有 7*7=49 个 if 语句,其中一些我需要转换为可能与另一个混淆的派生类,这看起来很容易编写错误的代码,并且给了我应该重新设计的气味。

请问我有什么想法吗?

// Domains.

public class Order{

private OrderTypeEnum orderType; 
// can be buy or sell

public OrderTypeEnum getOrderType() {
    return orderType;
}
public void setOrderType(OrderTypeEnum orderType) {
    this.orderType = orderType;
}
}

public class LimitOrder extends Order{

private Long unitPrice;

public Long getUnitPrice() {
    return unitPrice;
}
public void setUnitPrice(Long unitPrice) {
    this.unitPrice = unitPrice;
}
}

public class MarketOrder extends Order{

}

// Service.

public class TradeServiceImpl implements TradeService{

private TradeRepository tradeRepository;    


public Long getUnitPrice(Order buyOrder, Order sellOrder){

    if(buyOrder instanceof MarketOrder && sellOrder instanceof MarketOrder){
        return tradeRepository.getLastPrice();
    }

    if(buyOrder instanceof MarketOrder && sellOrder instanceof LimitOrder){
        return ((LimitOrder)sellOrder).getUnitPrice();
    }

    if(buyOrder instanceof LimitOrder && sellOrder instanceof MarketOrder){
        return ((LimitOrder)buyOrder).getUnitPrice();
    }

    if(buyOrder instanceof LimitOrder && sellOrder instanceof LimitOrder){
        return ((LimitOrder)buyOrder).getUnitPrice() + ((LimitOrder)sellOrder).getUnitPrice() /2;
    }

    return 0L;
}
}

【问题讨论】:

  • 这里需要的基本概念是,不是根据buyOrdersellOrder 的类来制作返回值,而是允许buyOrdersellOrder 来确定值自己。将您拥有的任何信息传递给其中一个或两个,并在Order 的每个子类中编写代码以确定如何生成返回值。

标签: java oop design-patterns refactoring


【解决方案1】:

首先,有两种情况可以合并为一种:当订单不同时:

 if(buyOrder instanceof MarketOrder && sellOrder instanceof LimitOrder){
        return ((LimitOrder)sellOrder).getUnitPrice();
    }

    if(buyOrder instanceof LimitOrder && sellOrder instanceof MarketOrder){
        return ((LimitOrder)buyOrder).getUnitPrice();
    }

收件人:

if(!buyOrder.getClass().equals(LimitOrder.getClass())){
        return ((LimitOrder)sellOrder).getUnitPrice();
    }

另一方面,您可以使用订单类作为包含函数对象的映射的索引。这样,您只需向此地图添加元素即可扩展您的功能。

您可以使用实现如下接口的匿名内部类来封装计算算法:

public interface IFunction {
    public Long execute(Order oA, Order oB);
}

并决定使用订单类访问此地图时执行哪些行为:

Map<Class, Map<Class, IFunction>> opClass2calcAlgorithm = new HashMap();

IFunction market_market = new IFunction() {

            @Override
            public Long execute(Order a, Order b) {
                return tradeRepository.getLastPrice();
            }
        };

IFunction market_limit = new IFunction() {

            @Override
            public Long execute(Order a, Order b) {
                return ((LimitOrder)a).getUnitPrice();
            }
        };

Map<Class, IFunction> marketMap = new HashMap();
marketMap.put(MarketOrder.class, market_market);
marketMap.put(LimitOrder.class, market_limit);
opClass2calcAlgorithm.put(marketMap);

最后,你的getUnitPrice 方法可以这样实现:

public Long getUnitPrice(Order buyOrder, Order sellOrder){

    long ret = 0L;

    Map<Class, IFunction> firstLevel = opClass2calcAlgorithm.get(buyOrder.getClass());
    if(firstLevel == null) return ret;
    IFunction calcAlg = firstLevel.get(sellOrder.getClass());
    if(calcAlg == null) return ret;

    ret = calcAlg.execute(buyOrder, sellOrder);

    return ret;
}

【讨论】:

    【解决方案2】:

    首先,在获取价格之前,您不需要将 buyOrder/sellOrder 转换为特定的类类型(因为多态性)。即

    public Long getUnitPrice(Order buyOrder, Order sellOrder){
    
        if(buyOrder instanceof MarketOrder && sellOrder instanceof MarketOrder){
            return tradeRepository.getLastPrice();
        }
    
        if(buyOrder instanceof MarketOrder && sellOrder instanceof LimitOrder){
            return sellOrder.getUnitPrice();
        }
    
        if(buyOrder instanceof LimitOrder && sellOrder instanceof MarketOrder){
            return buyOrder.getUnitPrice();
        }
    
        if(buyOrder instanceof LimitOrder && sellOrder instanceof LimitOrder){
            return (buyOrder.getUnitPrice() + sellOrder.getUnitPrice()) /2;
        }
    
        return 0L;
    }
    

    其次,对于计算逻辑,您可以使用工厂模式根据订单类型返回适当的计算器。不幸的是,我没有足够的关于您的代码的上下文来建议确切的代码。我建议您在线搜索工厂模式和策略模式。它们应该可以帮助您为代码设计更好的策略。

    【讨论】:

    • 感谢您的回答!在此示例中,Order 没有 getUnitPrice(),只有 LimitOrder。这就是为什么我仍然需要转换为子类来获取有关它们的信息。我会寻找你建议的工厂模式。
    猜你喜欢
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多