使用Quartz写一个简单的计时器,再使用观察者模式实现秒杀按钮启动的案例

题目

在某些重要的场景下,电商会开展定时秒杀活动,假设在6.18活动中携程网会对站内多种商品在同一时刻启动秒杀活动,请使用观察者模式,完成上述功能的设计类图和源码。
618携程秒杀按钮启动图

解题过程

分析

在这个案例里,我没有写出相应的界面,所有的功能都是使用类模拟相对应的模块,重点在于观察者模式的使用上。先上类图。这里我用Quartz写了一个简单的计时器,通过Cron表达式对秒杀时间进行设置。当系统到达秒杀的时间时,秒杀按钮才开启秒杀。然后封装两个ConcreteButton的具体观察者类来模拟秒杀模块的功能。
秒杀按钮启动类图
上面的类图大致分为两个部分:其中的类QuartzSeckill主要与Client搭配实现计时器的功能,下面的5个类为观察者模式的实现,具体如下:

  • Seckill:目标类(Subject),作为秒杀抽象目标类,其中的notifyseckill()为抽象通知方法;

  • SeckillTime:具体目标类(ConcreteSubject),通过继承Seckill类,实现具体的通知方法;

  • SeckillButton:观察者类(Observer):对Seckill类的改变做出反应,声明了更新数据的抽象方法response();

  • ConcreteButton、ConcreteButtonall:具体观察者类(ConcreteObserver),两个类的功能相同,都是实现SeckillButton类中response()的具体方法,只是两个类的一些方法上存在差异。

    实现

    以下是观察者模式的各个类,代码中含有解释的一些地方不再过多赘述:
    Seckill.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.ArrayList;
/**
* 秒杀抽象目标类
*
*/
public abstract class Seckill {
//定义一个ArrayList,用来存放秒杀按钮
protected ArrayList<SeckillButton> buttons = new ArrayList<SeckillButton>();

//注册方法
public void attach(SeckillButton button){
buttons.add(button);
}

//注销方法
public void detach(SeckillButton button){
buttons.remove(button);
}

//抽象通知方法,通知更新所有的按键
public abstract void notifyseckill();
}
12345678910111213141516171819202122

SeckillTime.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 具体目标类
*
*/
public class SeckillTime extends Seckill{

//秒杀是否开始状态标志
public boolean SeckillStart;
@Override
public void notifyseckill() {
System.out.println("618携程网的秒杀活动开始!");
System.out.println("------------------");
for(SeckillButton button:buttons){
button.response();
}
}
}
1234567891011121314151617

SeckillButton.java:

1
2
3
4
5
6
7
8
/**
* 抽象观察者类(抽象按钮)
*
*/
public interface SeckillButton {
void response();
}
1234567

ConcreteButton.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 具体观察者类(按钮类)
*
*/
public class ConcreteButton implements SeckillButton {

private String name;

public ConcreteButton(String name) {
this.name =name;
}
//获取按键名称
public String getName() {
return name;
}
@Override
public void response() {
System.out.println(name+"按钮开始秒杀!");
}
}
1234567891011121314151617181920

ConcreteButtonall.java

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 具体观察者类(all按钮类)
*
*/
public class ConcreteButtonall implements SeckillButton {

@Override
public void response() {
// TODO 自动生成的方法存根
System.out.println("全网按钮开始秒杀!");
}
}
123456789101112

做到这里其实已经基本实现了观察者模式了,如果不添加计时器,只需要再写一个以下的客户端类对各个类进行调用即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Client {
public static void main(String[] args){
Seckill seckill = new SeckillTime();

SeckillButton planeButton = new ConcreteButton("机票");
SeckillButton travelButton = new ConcreteButton("门票");
SeckillButton allButton = new ConcreteButtonall();

seckill.attach(planeButton);
seckill.attach(travelButton);
seckill.attach(allButton);

seckill.notifyseckill();
}
1234567891011121314

Quartz设计计时器

但是这里如果我们要用Quartz写一个计时器,就要将上面的客户端类进行修改。先说一下Quartz的简单运用。

首先,需要导入Quartz需要的包。如果创建的项目是maven项目的话,可以在pom.xml文件中直接加上Quartz的依赖即可。

1
2
3
4
5
6
7
8
<dependencies>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
1234567

如果不想建立maven项目,也可以自行下载jar包进行导入即可,我这里创建的是Web项目,所以直接将jar包导入到lib文件中即可,如果不是Web项目只需要自行创建一个lib文件就行,由于比较简单,这里就不说明了。
Quartz依赖的jar包
依赖的jar包可在这里http://www.quartz-scheduler.org/下载
如果网速不行可上https://www.jb51.net/softs/539791.html
实际用到的jar包有三个:quartz-2.2.1.jar,c3p0-0.9.1.1.jar,slf4j-api-1.6.6.jar

Quartz的简单理解就是在什么时间去做什么事情,它的使用思路分为三步:

  1. job - 任务 - - 你要做什么事?
  2. Trigger - 触发器 - - 你什么时候去做?
  3. Scheduler - 任务调度 - - 你什么时候需要去做什么事?

其中第3部是对前两步的整合,使其能合到一起,产生作用。要做一个开启秒杀按钮的计时器,我们就要先创建一个Job类,Job类中放的就是我们要做的事,这里我们需要它到预订的时间打开秒杀按钮,在观察者模式中也就是将上面客户端类的中目标类的通知方法notifyseckill()放到这个类中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Quartz计时器工作类
*
*/
public class QuartzSeckill implements Job {

@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
/*execute方法中为待做事务*/
// 获取当前时间:
System.out.println("当前时间为:"+new Date());
Seckill seckill = new SeckillTime();

SeckillButton planeButton = new ConcreteButton("机票");
SeckillButton travelButton = new ConcreteButton("门票");
SeckillButton allButton = new ConcreteButtonall();

seckill.attach(planeButton);
seckill.attach(travelButton);
seckill.attach(allButton);

seckill.notifyseckill();
}
}
123456789101112131415161718192021222324

再写一个客户端类Client,分别创建Job、Trigger、Scheduler对象,完成对代办事务设置什么时间,要做的事情,以及将两者整合到一起的工作。具体看代码中的注解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.util.Date;
import java.util.Scanner;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
/**
* 用户测试类
*
*/
public class Client {

public static void main(String[] args) throws Exception {
/**
* 这里写一个最简单的设置秒杀时间的方法,如果作为Web秒杀系统的应用可以写个后台管理系统设置秒杀时间,
* 然后系统获取时间,再引cron表达式的转化模块,就可以添加到下面的计时器使用。
*/
String[] str = new String[5];
System.out.print("请设置秒杀时间(月 日 时 分 秒):");
Scanner in = new Scanner(System.in);
for (int i = 0; i <5 ; i++) {
str[i]=in.next();
}

System.out.println("618携程网的秒杀活动将于2020年"+str[0]+"月"+str[1]+"日"+str[2]+"点"+str[3]+"分"+str[4]+"秒开始");
System.out.println("当前时间为:"+new Date());

/**
* 通过Quartz设计一个简单的计时器
*/
//1.创建Job对象:做什么事?
JobDetail job = JobBuilder.newJob(QuartzSeckill.class).build();

/**
* 简单的trigger触发时间:通过Quartz提供的一个方法来完成简单的重复调用,下方注解的代码句
* cron Trigger:按照Cron的表达式来给定触发时间 Cron表达式样式:"0 05 23 8 7 ? *"
*/
//2.创建Trigger对象,在什么时间做?
/*Trigger trigger = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build(); */

Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule(str[4]+" "+str[3]+" "+str[2]+" "+str[1]+" "+str[0]+" ? *")).build();

//3.创建Scheduler对象,在什么时间做什么事?
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);

//启动
scheduler.start();
}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

运行结果

运行结果图
以上就是运用Quartz和观察者模式对于启动秒杀按钮案例的所有内容,仅作为学习笔记做记录。如果能帮助到你,是我荣幸。有错误的地方也请大家帮忙指正,谢谢!