Java的策略模式

这篇博客通过一个餐厅打折优惠的例子介绍了如何使用Java实现策略模式。博主首先展示了传统做法,然后重构代码,实现了策略接口和具体策略类,利用枚举来存储折扣信息,并通过策略上下文选择合适的打折策略。最终,通过策略模式使得代码更加灵活和易于扩展。
摘要由CSDN通过智能技术生成

Java的策略模式

今天难得母亲大人休息,跟外婆妹妹她们一起去喝早茶,本来是很平常的一餐,但当结账时我看到了餐厅上写的打折优惠(具体部分没有拍照,大致是下面这样子),心里若有所思,觉得跟 Java 的策略模式很相像。刚好我也没有具体去实现过策略模式,趁着这个机会,自己试着实现了一下策略模式。

08:30 - 11:30 打 6.8 折	以结算时间为准
12:00 - 17:00 打 8.8 折	以入单时间为准
19:30 - 22:00 打 7.0 折	以入单时间为准

需求(自己添加的)
根据入单时间和结算时间,计算本次的消费金额

当我写完后,去网上看了一下具体的策略模式,发现网上的好像比我写的要简单一点,网上的是根据具体的策略手动 new 出来一个策略对象的🤣。下面贴一下我的代码,如果这不是策略模式的话,请轻喷!还请各位不吝赐教!!!

先贴一个最朴素的做法

public class StrategyMain {
    static Calendar startTime = Calendar.getInstance();
    static Calendar endTime = Calendar.getInstance();

    public static void main(String[] args) {

        startTime.set(2022, Calendar.OCTOBER, 24, 9, 0);
        endTime.set(2022, Calendar.OCTOBER, 24, 10, 32);

        Order order = new Order(126, new Date(startTime.getTimeInMillis()), new Date(endTime.getTimeInMillis()));

        if (inGo(order.getEndTime().getTime())) {
            System.out.println("消费金额为 " + order.getPay() * 0.68 + " 元,打 6.8 折");
        } else if (inAm(order.getStartTime().getTime())) {
            System.out.println("消费金额为 " + order.getPay() * 0.88 + " 元, 打 8.8 折");
        } else if (inPm(order.getStartTime().getTime())) {
            System.out.println("消费金额为 " + order.getPay() * 0.70 + " 元, 打 7.0 折");
        } else {
            System.out.println("消费金额为 " + order.getPay() + " 元,没有打折");
        }


    }

    // 08:30 - 11:30 打 6.8 折	以结算时间为准
    private static boolean inGo(long t) {
        startTime.set(2022, Calendar.OCTOBER, 24, 8, 30);
        endTime.set(2022, Calendar.OCTOBER, 24, 11, 30);

        return startTime.getTimeInMillis() <= t && t <= endTime.getTimeInMillis();
    }

    // 12:00 - 17:00 打 8.8 折	以入单时间为准
    private static boolean inAm(long t) {
        startTime.set(2022, Calendar.OCTOBER, 24, 12, 0);
        endTime.set(2022, Calendar.OCTOBER, 24, 17, 0);

        return startTime.getTimeInMillis() <= t && t <= endTime.getTimeInMillis();
    }

    // 19:30 - 22:00 打 7.0 折	以入单时间为准
    private static boolean inPm(long t) {
        startTime.set(2022, Calendar.OCTOBER, 24, 19, 30);
        endTime.set(2022, Calendar.OCTOBER, 24, 22, 0);

        return startTime.getTimeInMillis() <= t && t <= endTime.getTimeInMillis();
    }

输出结果

消费金额为 85.68 元,打 6.8 折

下面是使用了策略模式的做法

先定义订单实体类 Order (简化)

package com.zmz.entity;

import java.util.Date;

public class Order {

    private double pay; // 支付金额
    private Date startTime; // 开始时间
    private Date endTime; // 结束时间

    public Order() {
    }

    public Order(double pay, Date startTime, Date endTime) {
        this.pay = pay;
        this.startTime = startTime;
        this.endTime = endTime;
    }

    public double getPay() {
        return pay;
    }

    public void setPay(double pay) {
        this.pay = pay;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }

    @Override
    public String toString() {
        return "Order{" +
                "pay=" + pay +
                ", startTime=" + startTime +
                ", endTime=" + endTime +
                '}';
    }
}

策略接口

package com.zmz.strategy;

import com.zmz.entity.Order;

import java.util.Calendar;

public interface OrderStrategy {

    /**
     * 根据传入的开始时间和结束时间,选择具体的策略
     */
    default void strategy(Order order) {
        System.out.println("消费金额为 " + order.getPay() + " 元,没有打折");
    }

}

具体策略

// 08:30 - 11:30 打 6.8 折	以结算时间为准
package com.zmz.strategy.impl;

import com.zmz.entity.Order;
import com.zmz.strategy.StrategyEnum;
import com.zmz.strategy.OrderStrategy;

public class OrderStrategyGo implements OrderStrategy {

    @Override
    public void strategy(Order order) {
        System.out.println("消费金额为 " + order.getPay() * StrategyEnum.GO.getDiscount() + " 元,打 6.8 折");
    }

}

// 12:00 - 17:00 打 8.8 折	以入单时间为准
package com.zmz.strategy.impl;

import com.zmz.entity.Order;
import com.zmz.strategy.StrategyEnum;
import com.zmz.strategy.OrderStrategy;

public class OrderStrategyAm implements OrderStrategy {

    @Override
    public void strategy(Order order) {
        System.out.println("消费金额为 " + order.getPay() * StrategyEnum.AM.getDiscount() + " 元, 打 8.8 折");
    }

}

// 19:30 - 22:00 打 7.0 折	以入单时间为准
package com.zmz.strategy.impl;

import com.zmz.entity.Order;
import com.zmz.strategy.StrategyEnum;
import com.zmz.strategy.OrderStrategy;

public class OrderStrategyPm implements OrderStrategy {

    @Override
    public void strategy(Order order) {
        System.out.println("消费金额为 " + order.getPay() * StrategyEnum.PM.getDiscount() + " 元, 打 7.0 折");
    }

}

为了方便,写了一个枚举类

package com.zmz.strategy;

import com.zmz.strategy.impl.OrderStrategyAm;
import com.zmz.strategy.impl.OrderStrategyGo;
import com.zmz.strategy.impl.OrderStrategyPm;

public enum StrategyEnum {
    GO, // 08:30 - 11:30 打 6.8 折	以结算时间为准
    AM, // 12:00 - 17:00 打 8.8 折	以入单时间为准
    PM, // 19:30 - 22:00 打 7.0 折	以入单时间为准
    DEFAULT;

    private int low; // 满足该策略的时间最小分数
    private int height; // 满足该策略的时间最大分数
    private double discount; // 具体折扣
    private OrderStrategy orderStrategy; // 持有的策略

    static {
        init(StrategyEnum::GOInit);
        init(StrategyEnum::AMInit);
        init(StrategyEnum::PMInit);
        init(StrategyEnum::defaultInit);
    }

    StrategyEnum() {
    }

    private static void init(Runnable runnable) {
        runnable.run();
    }

    private static void GOInit() {
        GO.low = 8 * 60 + 30;
        GO.height = 11 * 60 + 30;
        GO.discount = 0.68;
        GO.orderStrategy = new OrderStrategyGo();
    }

    private static void AMInit() {
        AM.low = 12 * 60 + 0;
        AM.height = 17 * 60 + 0;
        AM.orderStrategy = new OrderStrategyAm();
        AM.discount = 0.88;
    }

    private static void PMInit() {
        PM.low = 19 * 60 + 30;
        PM.height = 22 * 60 + 0;
        PM.discount = 0.70;
        PM.orderStrategy = new OrderStrategyPm();
    }

    private static void defaultInit() {
        DEFAULT.discount = 1.0;
        DEFAULT.orderStrategy = new OrderStrategy() {
        };
    }

    public int getLow() {
        return low;
    }

    public int getHeight() {
        return height;
    }

    public double getDiscount() {
        return discount;
    }

    public OrderStrategy getStrategyService() {
        return orderStrategy;
    }
}

补充

枚举类的 low 和 height 属性说明

各个策略的选择只与订单的入单时间或结单时间的小时和分钟有关系,所以可以将具体的时间转换为一个唯一的值,简化选择策略的步骤。具体算法: 小时数 * 60 + 分钟数

策略上下文

package com.zmz.strategy;

import java.util.Date;

public class StrategyContext {


    public static OrderStrategy chooseStrategy(long start, long end) {
        switch (chooseEnum(start, end)) {
            case GO:
                return StrategyEnum.GO.getStrategyService();
            case AM:
                return StrategyEnum.AM.getStrategyService();
            case PM:
                return StrategyEnum.PM.getStrategyService();
            default:
                return StrategyEnum.DEFAULT.getStrategyService();

        }
    }

    private static StrategyEnum chooseEnum(long start, long end) {
        int low = new Date(start).getHours() * 60 + new Date(start).getMinutes();
        int height = new Date(end).getHours() * 60 + new Date(end).getMinutes();

        if (StrategyEnum.GO.getLow() < height && height <= StrategyEnum.GO.getHeight()) {
            return StrategyEnum.GO;
        } else if (StrategyEnum.AM.getLow() <= low && low < StrategyEnum.AM.getHeight()) {
            return StrategyEnum.AM;
        } else if (StrategyEnum.PM.getLow() <= low && low < StrategyEnum.PM.getHeight()) {
            return StrategyEnum.PM;
        }

        return StrategyEnum.DEFAULT;
    }


}

测试

package com.zmz;

import com.zmz.entity.Order;
import com.zmz.strategy.OrderStrategy;
import com.zmz.strategy.StrategyContext;

import java.util.Calendar;
import java.util.Date;

public class StrategyMain {
    static Calendar startTime = Calendar.getInstance();
    static Calendar endTime = Calendar.getInstance();

    public static void main(String[] args) {

        startTime.set(2022, Calendar.OCTOBER, 24, 9, 0);
        endTime.set(2022, Calendar.OCTOBER, 24, 10, 32);
        Order order = new Order(126, new Date(startTime.getTimeInMillis()), new Date(endTime.getTimeInMillis()));

        OrderStrategy orderStrategy = StrategyContext.chooseStrategy(order.getStartTime().getTime(), order.getEndTime().getTime());
        orderStrategy.strategy(order);


    }
}

输出

消费金额为 85.68 元,打 6.8 折

最后

只要知道订单的入单时间和结单时间,就能自动选择策略来确定具体的折扣!

策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在策略模式中,我们创建表示各种策略的对象和一个上下文对象,该对象可以根据其策略对象的不同行为而更改其执行算法。 以下是Java策略模式的示例代码: 首先,我们定义一个策略接口,该接口定义了一个方法calculate(),该方法将由具体策略类实现: ```java public interface Strategy { public int calculate(int num1, int num2); } ``` 然后,我们实现两个具体策略类,它们实现了策略接口并提供了自己的实现: ```java public class AddStrategy implements Strategy { public int calculate(int num1, int num2) { return num1 + num2; } } public class SubtractStrategy implements Strategy { public int calculate(int num1, int num2) { return num1 - num2; } } ``` 接下来,我们定义一个上下文类,该类将使用策略接口来执行算法: ```java public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int executeStrategy(int num1, int num2) { return strategy.calculate(num1, num2); } } ``` 最后,我们可以在客户端代码中使用上下文对象来执行算法: ```java public class Client { public static void main(String[] args) { Context context = new Context(new AddStrategy()); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); context = new Context(new SubtractStrategy()); System.out.println("10 - 5 = " + context.executeStrategy(10, 5)); } } ``` 输出结果为: ``` 10 + 5 = 15 10 - 5 = 5 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值