java 求 问 怎么在选定的日期内得到最合适的酒店程序

图片说明

就是一些if判断,这个很简单

看完需求,我大体思路如下:

一 需要抽象的对象:客户等级,客户等级价格,酒店,酒店销售策略,酒店星级,一周天数区间(因为是一周某几天对应一个价格,所以区间是一个对象)
二 以上对象的关系大体应该如下:
酒店应该有多种销售策略,因为工作日和周末的销售价格不一样,因此
图片说明

销售策略应该包含一个天数区间和多个客户等级价格,因为某一个策略对应的是一周的几天,并且不同的客户等级对应的价格也不一样,因此
图片说明

客户等级价格,应该包含一个客户等级和一个对应的价格,比如会员50元,普通客户100元,因此
图片说明

天数区间应该包含多个天数
图片说明

三.根据以上抽象的对象可以大体总结如下计算最优酒店的算法思路。
-输入:客户等级,开始时间,结束时间
-输出:酒店
1. 循环所有酒店,根据开始时间和结束时间还有客户等级算出每个酒店对应的价格,并且按照价格由低到高排序
2. 再按照酒店星级由高到低排序
3. 最后取第一个酒店即可

四.代码如下(代码主要采用Java8的流和新时间API,代码风格可能比较飘逸,请记得把JDK升到8)

测试类:

 public class HotelTest {

    public static void main(String[] args) {
        test(CustomerLevel.NORMAL, LocalDate.of(2009, 3, 16), LocalDate.of(2009, 3, 18));
        test(CustomerLevel.VIP, LocalDate.of(2016, 7, 31), LocalDate.of(2016, 8, 02));
    }

    public static void test(CustomerLevel customerLevel, LocalDate startDate, LocalDate endDate){
        Hotel hotel = HotelSelector.chooseCheapest(customerLevel, startDate, endDate);
        System.out.println(customerLevel.getName() + " " + startDate + "-" + endDate + "的最终选择的酒店:" + hotel.getName());
    }
}

执行结果:

图片说明

主体代码依次如下:

酒店类:

 @Getter
@AllArgsConstructor
public enum Hotel {

    // 如家
    HomeInn("如家", HotelStar.THREE, Arrays.asList(
            SaleStrategy.days(DaysInterval.wordDays).customerLevelPrices(
                    CustomerLevelPrice.level(CustomerLevel.NORMAL).price(110), CustomerLevelPrice.level(CustomerLevel.VIP).price(80)),
            SaleStrategy.days(DaysInterval.weekend).customerLevelPrices(
                    CustomerLevelPrice.level(CustomerLevel.NORMAL).price(90), CustomerLevelPrice.level(CustomerLevel.VIP).price(80))
    )),
    // 七天
    SevenDaysInn("七天", HotelStar.FOUR, Arrays.asList(
            SaleStrategy.days(DaysInterval.wordDays).customerLevelPrices(
                    CustomerLevelPrice.level(CustomerLevel.NORMAL).price(160), CustomerLevelPrice.level(CustomerLevel.VIP).price(110)),
            SaleStrategy.days(DaysInterval.weekend).customerLevelPrices(
                    CustomerLevelPrice.level(CustomerLevel.NORMAL).price(60), CustomerLevelPrice.level(CustomerLevel.VIP).price(50))
    )),
    // 汉庭
    HanTing("汉庭", HotelStar.FIVE, Arrays.asList(
            SaleStrategy.days(DaysInterval.wordDays).customerLevelPrices(
                    CustomerLevelPrice.level(CustomerLevel.NORMAL).price(210), CustomerLevelPrice.level(CustomerLevel.VIP).price(100)),
            SaleStrategy.days(DaysInterval.weekend).customerLevelPrices(
                    CustomerLevelPrice.level(CustomerLevel.NORMAL).price(150), CustomerLevelPrice.level(CustomerLevel.VIP).price(40))
    )),
    ;

    // 酒店名字
    private String name;

    // 酒店星级
    private HotelStar hotelStar;

    // 酒店的销售策略集合
    private List<SaleStrategy> saleStrategies;

    public Integer getHotelStarValue(){
        return this.hotelStar.getStarValue();
    }

    /**
     * 根据一个集合的天数和客户等级算出所有天数该酒店的价格和
     * @param dayOfWeekStream
     * @param customerLevel
     * @return
     */
    public Integer getPrice(Stream<DayOfWeek> dayOfWeekStream, CustomerLevel customerLevel){
        return dayOfWeekStream.map(dayOfWeek -> this.getPriceByDayOfWeek(dayOfWeek, customerLevel)).reduce(Integer::sum).get();
    }

    /**
     * 根据当前的天数和客户等级,获取这一天,这个酒店的价格
     * @param dayOfWeek
     * @param customerLevel
     * @return
     */
    private Integer getPriceByDayOfWeek(DayOfWeek dayOfWeek, CustomerLevel customerLevel){
        return this.saleStrategies.stream().filter(saleStrategy -> saleStrategy.getDaysInterval().contain(dayOfWeek))
                                           .findFirst()
                                           .map(saleStrategy -> saleStrategy.getCustomerLevelPrice(customerLevel))
                                           .map(CustomerLevelPrice::getPrice)
                                           .get();
    }
}

酒店星级:

 @Getter
@AllArgsConstructor
public enum HotelStar {

    ONE(1),
    TWO(2),
    THREE(3),
    FOUR(4),
    FIVE(5);

    private Integer starValue;
}

酒店销售策略:

 @Getter
@Setter
public class SaleStrategy {

    // 当前销售策略适应的天数区间
    private DaysInterval daysInterval;

    // 不同客户等级对应的价格集合
    private List<CustomerLevelPrice> customerLevelPrices;

    public static SaleStrategy days(DaysInterval daysInterval){
        return new SaleStrategy(daysInterval);
    }

    public SaleStrategy customerLevelPrices(CustomerLevelPrice ... customerLevelPrices){
        this.customerLevelPrices = Arrays.asList(customerLevelPrices);
        return this;
    }

    public CustomerLevelPrice getCustomerLevelPrice(CustomerLevel customerLevel){
        return this.customerLevelPrices.stream().filter(customerLevelPrice -> customerLevelPrice.getCustomerLevel().equals(customerLevel)).findFirst().get();
    }

    private SaleStrategy(DaysInterval daysInterval) {
        this.daysInterval = daysInterval;
    }
}

天数区间:

 public class DaysInterval {

    // 包含的一周哪些天
    private List<DayOfWeek> days;

    // 工作日区间(包括周一,周二,周三,周四,周五)
    public static DaysInterval wordDays = of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY);

    // 周末区间(包括周六,周日)
    public static DaysInterval weekend = of(DayOfWeek.FRIDAY, DayOfWeek.SUNDAY);

    public static DaysInterval of(DayOfWeek ... dayOfWeeks){
        return new DaysInterval(Arrays.asList(dayOfWeeks));
    }

    public boolean contain(DayOfWeek dayOfWeek){
        return this.days.contains(dayOfWeek);
    }

    private DaysInterval(List<DayOfWeek> days) {
        this.days = days;
    }
}

客户等级价格:

 @Getter
public class CustomerLevelPrice {

    // 客户等级
    private CustomerLevel customerLevel;

    // 对应的价格
    private Integer price;

    public static CustomerLevelPrice level(CustomerLevel customerLevel){
        return new CustomerLevelPrice(customerLevel);
    }

    public CustomerLevelPrice price(Integer price){
        this.price = price;
        return this;
    }

    private CustomerLevelPrice(CustomerLevel customerLevel) {
        this.customerLevel = customerLevel;
    }
}

客户等级:

 @Getter
@AllArgsConstructor
public enum CustomerLevel {
    // 普通客户
    NORMAL("普通客户"),
    // VIP客户
    VIP("会员客户");

    private String name;
}

酒店选择器:

 public class HotelSelector {

    /**
     * 根据当前客户级别,和客户准备入住酒店的开始时间和结束时间,筛选出当前最便宜的酒店
     * @param customerLevel
     * @param startDate
     * @param endDate
     * @return
     */
    public static Hotel chooseCheapest(CustomerLevel customerLevel, LocalDate startDate, LocalDate endDate){
        return Arrays.stream(Hotel.values())
                     // 先按照每个酒店的最终价格升序排列
                     .sorted(Comparator.comparing((Hotel hotel) -> hotel.getPrice(createStream(startDate, endDate), customerLevel))
                             // 若价格相等,再按照每个酒店的星级降序排列
                             .thenComparing(Comparator.comparing(Hotel::getHotelStarValue).reversed()))
                     // 排列后取第一个即可
                     .findFirst().get();

    }

    /**
     * 将入店开始时间和离店时间转化为天数的流,方便后续计算
     * @param startDate
     * @param endDate
     * @return
     */
    public static Stream<DayOfWeek> createStream(LocalDate startDate, LocalDate endDate){
        return Stream.iterate(startDate, localDate -> localDate.plusDays(1))
                     .limit(ChronoUnit.DAYS.between(startDate, endDate) + 1)
                     .map(LocalDate::getDayOfWeek);
    }
}

五. 之所以有这么多的类,主要方便扩展,当前可快速扩展的点有:
1.销售区间可扩展,可自由选择周一到周末的任意几天为天数区间
2.客户等级可扩展,可扩展普通用户,黄金用户,白金用户等,不同用户也可以设置不同的价格

最后,本来代码在idea里写的挺漂亮的,不知道贴出来看着却这么丑...哎...

这个我觉的如果要实现完全达到自动化,这可能需要使用大数据知识让程序自动去判断吧!!!!