组合设计模式

阿里p7面试的一道题:

编程题目: 出租车起步价14元,含3公里 起步价之后,每公里2.5元
晚上11点之后(含),次日6点前(不含)起步价18元,含3公里。计价以上车时间为准,不考虑乘坐期间从白天到晚上的情况。
晚上起步价之后,每公里3元 10公里之后,白天每公里3.5元,晚上每公里4.7元
外环的出租车10公里之外的价格与10公里之内相同。外环与内环是出租车的属性,也就是说一辆外环的出租车在内环拉了客人,并行使到了外环,整段旅程都是外环的计费策略。

请编写代码表示出上述的功能 要求:

  1. 体现出良好的设计,使得代码具有一定的灵活性和扩展性
  2. 提供测试代码

本文使用组合模式
考虑内外环是属性,创建枚举类; 属性内环外环;
根据题目可以看出,白天夜晚是不变的,暂时无可扩展性,价格,公里是多变的 需要一定可变性来维持,;
最终对外提供的接口 一定是这样的:

@Service
public class TaxiPriceServiceImpl implements TaxiPriceService, ApplicationContextAware {
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public BigDecimal calculatePrice(Date abroadTime, BigDecimal distance, Taxi taxi) {
        List<AbstractDistanceHandler> distanceHandlerList = new ArrayList<>();

        if (distance.compareTo(Distance.STARTING_DISTANCE) <= BigDecimal.ZERO.intValue()) { //小于三公里的金钱
            distanceHandlerList.add(applicationContext.getBean(StartingDistanceHandler.class));
        } else if (distance.compareTo(Distance.ADJUST_DISTANCE) <= BigDecimal.ZERO.intValue()) { //小于10公里的金钱
            distanceHandlerList.add(applicationContext.getBean(StartingDistanceHandler.class));
            distanceHandlerList.add(applicationContext.getBean(BeforeAdjustHandler.class));
        } else {   //大于10公里的金钱
            distanceHandlerList.add(applicationContext.getBean(StartingDistanceHandler.class));
            distanceHandlerList.add(applicationContext.getBean(BeforeAdjustHandler.class));
            distanceHandlerList.add(applicationContext.getBean(AfterAdjustHandler.class));
        }
        //取到金钱list 开始相加
        BigDecimal totalPrice = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(distanceHandlerList)) {
            for (AbstractDistanceHandler distanceHandler : distanceHandlerList) {
                totalPrice = totalPrice.add(distanceHandler.calculatePrice(abroadTime, distance, taxi));
                System.out.println("总和"+totalPrice);
            }
        }

        return totalPrice;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

开始楼代码: 创建一个抽象类,出租车类

/** 出租类
 * Created by z1761 on 2018/10/11.
 */
public abstract class AbstractDistanceHandler {

    public BigDecimal calculatePrice(Date abroadTime, BigDecimal distance, Taxi taxi) {
        BigDecimal multiply = this.getUnitPrice(abroadTime, taxi).multiply(this.calculateDistance(distance));
        System.out.println("计算出 单价和公里相乘的价格"+multiply);
        return multiply;
    }

    public abstract BigDecimal getUnitPrice(Date abroadTime, Taxi taxi); //每公里的单价

    public abstract BigDecimal calculateDistance(BigDecimal distance); //行驶距离
}

三个实现类,分别是3公里内,10公里内,10公里外

/** 起步价
 * Created by z1761 on 2018/10/11.
 */
@Service
public class StartingDistanceHandler extends AbstractDistanceHandler {

    @Autowired
     AbroadTimeService abroadTimeServicess;
    @Autowired
     ApplicationContext applicationContextss;

    @Override
    public BigDecimal getUnitPrice(Date abroadTime, Taxi taxi) {
        AbroadTimeService bean = applicationContextss.getBean(AbroadTimeService.class);

        AbroadTimeServiceImpl abroadTimeService = new AbroadTimeServiceImpl();
        //AbroadTimeTypeEnum abroadTimeType = abroadTimeService.determineAbroadTimeType(abroadTime);

        //计算时间是白天还是晚上
        AbroadTimeTypeEnum abroadTimeType = this.abroadTimeServicess.determineAbroadTimeType(abroadTime);

        if (AbroadTimeTypeEnum.DAY.equals(abroadTimeType)) {
            return Price.DAY_STARTING_PRICE;
        }

        if (AbroadTimeTypeEnum.NIGHT.equals(abroadTimeType)) {
            return Price.NIGHT_STARTING_PRICE;
        }

        return BigDecimal.ZERO;
    }

    @Override
    public BigDecimal calculateDistance(BigDecimal distance) {
        return BigDecimal.ONE;
    }
}

十公里内

/** 大于三公里 小于10公里
 * Created by z1761 on 2018/10/11.
 */
@Service
public class BeforeAdjustHandler extends AbstractDistanceHandler {

    @Autowired
    private AbroadTimeService abroadTimeService;

    @Override
    public BigDecimal getUnitPrice(Date abroadTime, Taxi taxi) {
        //计算时间是白天还是晚上
        AbroadTimeTypeEnum abroadTimeType = this.abroadTimeService.determineAbroadTimeType(abroadTime);

        if (AbroadTimeTypeEnum.DAY.equals(abroadTimeType)) {
            return Price.DAY_UNIT_PRICE_BEFORE_ADJUST;
        }

        if (AbroadTimeTypeEnum.NIGHT.equals(abroadTimeType)) {
            return Price.NIGHT_UNIT_PRICE_BEFORE_ADJUST;
        }

        return BigDecimal.ZERO;
    }

    @Override
    public BigDecimal calculateDistance(BigDecimal distance) {
        if (distance.compareTo(BigDecimal.TEN)>0) {
            return new BigDecimal(BigDecimal.ROUND_UNNECESSARY);
        }
        return distance.subtract(Distance.STARTING_DISTANCE);
    }
}

十公里外,看提所示 外环和内环 10公里内白天夜晚价格一样,只有10公里之外价格才不一样

/** 10公里之后的价格
 * Created by z1761 on 2018/10/11.
 */
@Service
public class AfterAdjustHandler extends AbstractDistanceHandler {

    @Autowired
    private AbroadTimeService abroadTimeService;

    @Override
    public BigDecimal getUnitPrice(Date abroadTime, Taxi taxi) {
        //计算时间是白天还是晚上
        AbroadTimeTypeEnum abroadTimeType = this.abroadTimeService.determineAbroadTimeType(abroadTime);
        TravelScopeEnum travelScope = taxi.getTravelScope();
        //判断是白天并且是内换车
        if (AbroadTimeTypeEnum.DAY.equals(abroadTimeType) && TravelScopeEnum.INNER_LOOP.equals(travelScope)) {
            return Price.DAY_UNIT_PRICE_AFTER_ADJUST;
        }
        //判断是白天并且是外环车
        if (AbroadTimeTypeEnum.DAY.equals(abroadTimeType) && TravelScopeEnum.OUTER_LOOP.equals(travelScope)) {
            return Price.DAY_UNIT_PRICE_BEFORE_ADJUST;
        }
        //判断是晚上并且是内环车
        if (AbroadTimeTypeEnum.NIGHT.equals(abroadTimeType) && TravelScopeEnum.INNER_LOOP.equals(travelScope)) {
            return Price.NIGHT_UNIT_PRICE_AFTER_ADJUST;
        }
        //判断是晚上并且是外车
        if (AbroadTimeTypeEnum.NIGHT.equals(abroadTimeType) && TravelScopeEnum.OUTER_LOOP.equals(travelScope)) {
            return Price.NIGHT_UNIT_PRICE_BEFORE_ADJUST;
        }

        return BigDecimal.ZERO;
    }

    @Override
    public BigDecimal calculateDistance(BigDecimal distance) {
        return distance.subtract(Distance.ADJUST_DISTANCE);
    }
}

每个类里都有计算时间的接口

/** 计算时接口
 * Created by z1761 on 2018/10/11.
 */
public interface AbroadTimeService {

    AbroadTimeTypeEnum determineAbroadTimeType(Date abroadTime);

    boolean isPeak(Date abroadTime);
}

impl

/** 计算白天还是黑夜
 * Created by z1761 on 2018/10/12.
 */
@Service
public class AbroadTimeServiceImpl implements AbroadTimeService {
    @Override
    public AbroadTimeTypeEnum determineAbroadTimeType(Date abroadTime) {
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH");
        String format = simpleDateFormat.format(date);
        Integer hour = Integer.valueOf(format);
        if (hour > AbroadTime.DAY_START || hour < AbroadTime.DAY) {
            return null;
        }
        //大于六点 小于23点 是在白天
        if (hour> AbroadTime.DAY_START&&hour<=AbroadTime.NIGHT_START) {
            return AbroadTimeTypeEnum.DAY;
        } else if (hour<=AbroadTime.DAY_START||hour<AbroadTime.NIGHT_START) {
            return AbroadTimeTypeEnum.NIGHT;
        }
        return null;
    }

    @Override
    public boolean isPeak(Date abroadTime) {
        return false;
    }
}

因为只是一个demo 所有没有做null判断;

三个 constant ,价格,公里,时间,

/** 时间
 * Created by z1761 on 2018/10/11.
 */
public class AbroadTime {

    public static final int DAY_START = 6;
    public static final int NIGHT_START = 23;
    public static final int DAY = 0;
    public static final int NIGHT=24;
}


/** 公里
 * Created by z1761 on 2018/10/11.
 */
public class Distance {

    public static BigDecimal STARTING_DISTANCE = new BigDecimal(3);
    public static BigDecimal ADJUST_DISTANCE = new BigDecimal(10);
}

/** 价格
 * Created by z1761 on 2018/10/11.
 */
public class Price {

    public static final BigDecimal DAY_STARTING_PRICE = new BigDecimal(14);
    public static final BigDecimal DAY_UNIT_PRICE_BEFORE_ADJUST = new BigDecimal(2.5);
    public static final BigDecimal DAY_UNIT_PRICE_AFTER_ADJUST = new BigDecimal(3.5);

    public static final BigDecimal NIGHT_STARTING_PRICE = new BigDecimal(18);
    public static final BigDecimal NIGHT_UNIT_PRICE_BEFORE_ADJUST = new BigDecimal(3);
    public static final BigDecimal NIGHT_UNIT_PRICE_AFTER_ADJUST = new BigDecimal(4.7);
}

如果需求有点改变,或者出现高峰期的价格波动,则采用装饰者模式+组合模式;

/** 如果是高峰期 按照高峰期来算 ,早上9.  10点 晚上 7-9点
 * 这个时间段都在白天路段。
 * 举例 10公里内的
 * @Primary 这个注解告诉spring 假如有多个实现或者继承的话,先去这里找
 * Created by z1761 on 2018/10/11.
 */
@Component
@Primary
public class BeforeAdjustHandlerDecorator extends AbstractDistanceHandler {

    @Autowired
    private AbroadTimeService abroadTimeService;

    @Autowired
    private BeforeAdjustHandler beforeAdjustHandler;

    @Override
    public BigDecimal getUnitPrice(Date abroadTime, Taxi taxi) {
        //在这里进行判断 时间是否在高峰期内,在的话 return单价,假设高峰期单价为TEN(10)
        if (abroadTimeService.isPeak(abroadTime)) {
            return BigDecimal.TEN;
        }
        //不在的话 高峰期又在白天内; 所已调用
        return this.beforeAdjustHandler.getUnitPrice(abroadTime, taxi);
    }

    @Override
    public BigDecimal calculateDistance(BigDecimal distance) {
        return this.beforeAdjustHandler.calculateDistance(distance);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值