模拟电子手表--结合MVC架构和状态模式

本文介绍了一种基于状态模式和MVC架构的电子手表功能实现方案,包括时间显示、跑秒表、日期设定、时间设定、闹铃设定等功能,通过状态模式简化了复杂的按键操作逻辑。

电子手表一般有4个按键,有多种状态,在不同的状态下各个按键有不同的功能,若采用if-then结构则系统将变得特别复杂,下面考虑采用状态模式实现其功能,又因为其涉及众多的交互,所以系统采用MVC架构进行输入、输出管理。

系统功能如下:                                                                                                                                                                                 *在正常时间显示状态,按住START键,显示日期,按住RESET键,显示闹铃时间
*跑秒表使用方法:在正常时间显示下,按MODE键1次进入跑秒表工作模式,按START键跑表工作,再按START键跑表停止,显示计时数字,按RESET键数字清零,MODE键返回正常时间显示。
*日期设定: 在正常时间显示下,按MODE键2次,进入时间设定状态,天闪动,按START键,校对天,按RESET键,月闪动,按STSRT键校对月,再按RESET,年闪动,按START键和RESET,校对年,按MODE键返回
*时间设定:在正常时间显示下,按MODE键3次,进入时间设定状态,秒闪动,按START键,校对秒,按RESET键,分钟闪动,按STSRT键校对分钟,再按RESET,小时闪动,按START键校对小时,按MODE键返回
*闹铃时间设定:在正常时间显示下,按MODE键4次,闹铃开启/关闭闪动,再按START键可选择开启/关闭,按RESET键1次,分钟闪动,再按STSRT键设定分钟,按RESET键,再按动STSRT键,小时闪动,可设定小时,按MODE键返回
*闹铃:在闹铃响铃时,按任意键,闹铃停止。

系统代码如下,首先是界面:

<!DOCTYPE html>
<html>
<head>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="myclock.js"></script>
<style>
#screen{
text-align:center;
height:40px;
width:120px;
background-color:darkcyan;
}

</style>
</head>
<body>
<table>
<tr>
<td id='light'>夜光</td><td ></td><td id='start'>启动</td>
</tr>
<tr>
<td></td><td id='screen'></td><td ></td>
</tr>
<tr>
<td id='mode'>模式</td><td ></td><td id='reset'>复位</td>
</tr>
</table>
</body>
</html>

下面是控制代码:

//myclock.js
$(document).ready(function () {
	var Model = {
		state: '',

		milsecond: 0,
		second: 0,
		minute: 0,
		hour: 0,
		total_second: 0,

		Alarm_on: 0,
		Alarm_minute: 0,
		Alarm_hour: 0,

		start_stopwatch: 0,
		stopwatch_milsecond: 0,
		stopwatch_second: 0,
		stopwatch_minute: 0,

		month_days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],

		year: 2000,
		month: 1,
		day: 1,

		configure_YMD: 0, //0->year,1->month,2->day
		configure_year: 2000,
		configure_month: 1,
		configure_day: 1,
		configure_HMS: 0, //0->hour,1->minute,3->second
		configure_hour: 0,
		configure_minute: 0,
		configure_second: 0,
		configure_Alarm: 0, //0->hour,1->minute
		configure_Alarm_hour: 0,
		configure_Alarm_minute: 0,
		configure_Alarm_on: 0,
		add_one_day: function () {
			if (this.day < this.month_days[this.month - 1]) {
				this.day++;
			} else { //最后一天
				this.day = 1;
				if (12 == this.month) {
					this.month = 1;
					this.year++;
					if ((this.year % 400 == 0) || (this.year % 100 != 0 && this.year % 4 == 0)) {
						this.month_days[1] = 29;
					} else {
						this.month_days[1] = 28;
					}
				} else {
					this.month++;
				}
			}
		},
		set_year: function (year) {
			if (year <= 0)
				year = 1;
			if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0))
				Model.month_days[1] = 29;
			else
				Model.month_days[1] = 28;
			Model.year = year;
			Model.configure_year = year;
		},
		add: function () {
			this.milsecond += 10;
			if (this.milsecond >= 1000) {
				this.second++;
				this.milsecond = 0;
			}
			if (this.second >= 60) {
				this.minute++;
				this.second = 0;
			}
			if (this.minute >= 60) {
				this.hour++;
				this.minute = 0;
			}
			if (this.hour >= 24) {
				this.hour = 0;
				this.add_one_day();
			}

			if (this.start_stopwatch == 1) {
				this.stopwatch_milsecond += 10;
				if (this.stopwatch_milsecond >= 1000) {
					this.stopwatch_second++;
					this.stopwatch_milsecond = 0;
				}
				if (this.stopwatch_second >= 60) {
					this.stopwatch_minute++;
					this.stopwatch_second = 0;
				}
			}
			if ((1 == this.Alarm_on) && (this.hour == this.Alarm_hour) && (this.minute == this.Alarm_minute) && (0 == this.second) && (0 == this.milsecond)) {
				Controller.FSM.ChangeState(AlarmState);
			}
		},
	};
	var View = {
		View: function () {},
		View_NormalState: function () {
			$("#screen").html(('0' + Model.hour).substr(-2) + ':' + ('0' + Model.minute).substr(-2) + ':' + ('0' + Model.second).substr(-2));
		},
		View_Date_Info: function () {
			$("#screen").html(('00000' + Model.year).substr(-4) + '年' + ('0' + Model.month).substr(-2) + '月' + ('0' + Model.day).substr(-2) + '日');
		},
		View_Alarm_Info: function () {
			$("#screen").html(('00000' + Model.Alarm_hour).substr(-2) + ':' + ('0' + Model.Alarm_minute).substr(-2) + (Model.Alarm_on == 1 ? "  ON" : " OFF"));
		},
		flash: 0,
		View_AlarmState: function () {
			this.flash++;
			$("#screen").html(('0' + Model.hour).substr(-2) + ':' + ('0' + Model.minute).substr(-2) + ':' + ('0' + Model.second).substr(-2));
			var color = Math.trunc(this.flash / 50) % 2 ? "yellow" : "white";

			$("table").css("background", color);
		},
		View_Stopwatch: function () {
			$("#screen").html("<span class='blink' ><=></span>" + ('00000' + Model.stopwatch_minute).substr(-2) + ':' + ('0' + Model.stopwatch_second).substr(-2) + ':' + (1000 + Model.stopwatch_milsecond + '0').substr(1, 2));
		},
		View_Configure_YMD: function () {
			var html = "";
			var year = ('00000' + Model.configure_year).substr(-4);
			var month = ('0' + Model.configure_month).substr(-2);
			var day = ('0' + Model.configure_day).substr(-2);
			switch (Model.configure_YMD) {
			case 2: //year
				html = "<span class='blink' >" + year + "</span>年" + month + "月" + day + "日";
				break;
			case 1: //month
				html = year + "年<span class='blink' >" + month + "</span>月" + day + "日";
				break;
			case 0: //day
				html = year + "年" + month + "月<span class='blink' >" + day + "</span>日";
				break;
			}

			$("#screen").html(html);
		},
		View_Configure_HMS: function () {
			var html = "";
			var hour = ('0' + Model.configure_hour).substr(-2);
			var minute = ('0' + Model.configure_minute).substr(-2);
			var second = ('0' + Model.configure_second).substr(-2);
			switch (Model.configure_HMS) {
			case 2: //hour
				html = "<span class='blink' >" + hour + "</span>:" + minute + ":" + second;
				break;
			case 1: //minute
				html = hour + ":<span class='blink' >" + minute + "</span>:" + second;
				break;
			case 0: //second
				html = hour + ":" + minute + ":<span class='blink' >" + second + "</span>";
				break;
			}

			$("#screen").html(html);
		},
		View_Configure_Alarm: function () {
			var html = "";
			var hour = ('0' + Model.configure_Alarm_hour).substr(-2);
			var minute = ('0' + Model.configure_Alarm_minute).substr(-2);
			var Alarm_on = Model.configure_Alarm_on == 1 ? "  ON" : " OFF";
			switch (Model.configure_Alarm) {
			case 2: //hour
				html = "<span class='blink' >" + hour + "</span>:" + minute + Alarm_on;
				break;
			case 1: //minute
				html = hour + ":<span class='blink' >" + minute + "</span>" + Alarm_on;
				break;
			case 0: //minute
				html = hour + ":" + minute + "<span class='blink' >" + Alarm_on + "</span>";
				break;
			}

			$("#screen").html(html);
		},
		blink: 0,
		View_Blink: function () {
			//if ((Model.state).substr(0, 9) != "Configure")
			//	return;
			var color = View.blink ? "darkcyan" : "black";
			View.blink = 1 - View.blink;
			$(".blink").css("color", color);
		},

	};

	var Controller = {
		timer: null,
		FSM: null,
		click: function (e) {
			Controller.FSM.Update(e);
		},
		light: function (e) {
			if (e.type == "mousedown") {
				$("table").css("background", "yellow");
			} else {
				$("table").css("background", "white");
			}
		},
	};
	var StateMachine = {
		m_PreviousState: {
			name: "",
			Enter: function () {},
			Exit: function () {},
			Update: function (e) {},
		},
		m_CurrentState: {
			name: "",
			Enter: function () {},
			Exit: function () {},
			Update: function (e) {},
		},
		Update: function (e) {
			if (this.m_CurrentState != null)
				this.m_CurrentState.Update(e);
		},
		ChangeState: function (s) {
			document.title = s.name;
			this.m_PreviousState = this.m_CurrentState;
			this.m_CurrentState.Exit();
			this.m_CurrentState = s;
			this.m_CurrentState.Enter();
		},
		RevertToPreviousState: function () {
			this.ChangeState(this.m_PreviousState);
		},

	};
	var NormalState = {
		name: "NormalState",
		Enter: function () {
			Model.state = 'NormalState';
			View.View = View.View_NormalState;
		},
		Exit: function () {},
		Update(e) {
			if (e.type == "mousedown") {
				switch (e.target.id) {
				case "mode": //进入跑秒状态
					Controller.FSM.ChangeState(StopwatchState);
					break;
				case "reset": //显示闹钟时间
					View.View = View.View_Alarm_Info;
					break;
				case "start": //显示日期
					View.View = View.View_Date_Info;
					break;
				}
			} else { //mouse up
				switch (e.target.id) {

				case "reset": //显示闹钟时间
				case "start": //显示日期
					View.View = View.View_NormalState;
					break;
				}
			}
		}
	};
	var AlarmState = {
		name: "AlarmState",
		Enter: function () {
			Model.state = 'AlarmState';
			View.View = View.View_AlarmState;
		},
		Exit: function () {
			$("table").css("background", "white");
		},
		Update: function (e) {
			if (e.type == "mouseup") {
				return;
			}
			Controller.FSM.RevertToPreviousState();
		},
	};
	var StopwatchState = {
		name: "StopwatchState",
		Enter: function () {
			Model.state = 'StopwatchState';
			View.View = View.View_Stopwatch;
		},
		Exit: function () {},
		Update(e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //进入设置年月日状态
				Controller.FSM.ChangeState(ConfigureState_YMD);
				break;
			case "reset": //进入复位暂停状态
				Model.stopwatch_milsecond = 0;
				Model.stopwatch_second = 0;
				Model.stopwatch_minute = 0;
				Model.start_stopwatch = 0;
				Controller.FSM.ChangeState(StopwatchState_pause);
				break;
			case "start": //开始计时
				Controller.FSM.ChangeState(StopwatchState_start);
				break;
			}
		}
	};
	var StopwatchState_start = {
		name: "StopwatchState_start",
		Enter: function () {
			Model.start_stopwatch = 1;
		},
		Exit: function () {},
		Update: function (e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //进入正常状态
				Controller.FSM.ChangeState(NormalState);
				break;
			case "reset": //进入复位暂停状态
				Model.stopwatch_milsecond = 0;
				Model.stopwatch_second = 0;
				Model.stopwatch_minute = 0;
				Model.start_stopwatch = 0;
				Controller.FSM.ChangeState(StopwatchState_pause);
				break;
			case "start": //进入暂停状态
				Controller.FSM.ChangeState(StopwatchState_pause);
				break;
			}
		},
	};
	var StopwatchState_pause = {
		name: "StopwatchState_pause",
		Enter: function () {
			Model.start_stopwatch = 0;
		},
		Exit: function () {},
		Update: function (e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //进入正常状态
				Controller.FSM.ChangeState(NormalState);
				break;
			case "reset": //进入复位暂停状态
				Model.stopwatch_milsecond = 0;
				Model.stopwatch_second = 0;
				Model.stopwatch_minute = 0;
				Model.start_stopwatch = 0;
				break;
			case "start": //开始计时
				Controller.FSM.ChangeState(StopwatchState_start);
				break;
			}
		},
	};
	var ConfigureState_YMD = {
		name: "ConfigureState_YMD",
		Enter: function () {
			Model.configure_year = Model.year;
			Model.configure_month = Model.month;
			Model.configure_day = Model.day;
			Model.configure_YMD = 0;
			Model.state = 'ConfigureState_YMD';
			View.View = View.View_Configure_YMD;
		},
		Exit: function () {
			Model.year = Model.configure_year;
			Model.month = Model.configure_month;
			Model.day = Model.configure_day;
			Model.configure_YMD = 0;
		},
		Update(e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //进入设置时分秒状态
				Controller.FSM.ChangeState(ConfigureState_HMS);
				break;
			case "reset": //调节设置项
				Model.configure_YMD++;
				if (3 == Model.configure_YMD)
					Model.configure_YMD = 0;

				break;
			case "start": //调节参数
				switch (Model.configure_YMD) {
				case 2: //year 年要加加减减
					Controller.FSM.ChangeState(ConfigureState_YMD_year);
					break;
				case 1: //month
					Model.configure_month++;
					if (13 == Model.configure_month)
						Model.configure_month = 1;

					break;
				case 0: //day
					Model.configure_day++;
					if (Model.configure_day > Model.month_days[Model.configure_month - 1])
						Model.configure_day = 1;
					break;
				}
				break;
			}
		}
	};
	var ConfigureState_YMD_year = {
		name: "Configure_YMD_year",
		Enter: function () {
			Model.configure_year++;
			Model.configure_YMD = 2;
		},
		Exit: function () {
			Model.year = Model.configure_year;
			Model.month = Model.configure_month;
			Model.day = Model.configure_day;
			Model.configure_YMD = 0;
			Model.state = 'ConfigureState_YMD';
			View.View = View.View_Configure_YMD;
		},
		Update: function (e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //返回设置年月日状态
				Controller.FSM.ChangeState(ConfigureState_YMD);
				break;
			case "reset":
				Model.set_year(Model.year - 1);
				break;
			case "start":
				Model.set_year(Model.year + 1);
				break;
			}
		},
	};
	var ConfigureState_HMS = {
		name: "ConfigureState_HMS",
		Enter: function () {
			Model.configure_hour = Model.hour;
			Model.configure_minute = Model.minute;
			Model.configure_second = Model.second;
			Model.configure_HMS = 0;
			Model.state = 'ConfigureState_HMS';
			View.View = View.View_Configure_HMS;
		},
		Exit: function () {
			Model.hour = Model.configure_hour;
			Model.minute = Model.configure_minute;
			Model.second = Model.configure_second;
			Model.configure_HMS = 0;
		},
		Update(e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //进入设置闹钟状态
				Controller.FSM.ChangeState(ConfigureState_Alarm);
				break;
			case "reset": //调节设置项
				Model.configure_HMS++;
				if (3 == Model.configure_HMS)
					Model.configure_HMS = 0;
				break;
			case "start": //开始配置时间
				switch (Model.configure_HMS) {
				case 2: //hour
					Model.configure_hour++;
					if (Model.configure_hour == 24)
						Model.configure_hour = 0;
					break;
				case 1: //minute
					Model.configure_minute++;
					if (60 == Model.configure_minute)
						Model.configure_minute = 0;
					break;
				case 0: //second
					Model.configure_second++;
					if (60 == Model.configure_second)
						Model.configure_second = 0;
					break;
				}
				break;
			}
		}
	};
	var ConfigureState_Alarm = {
		name: "ConfigureState_Alarm",
		Enter: function () {
			Model.configure_Alarm_hour = Model.Alarm_hour;
			Model.configure_Alarm_minute = Model.Alarm_minute;
			Model.configure_Alarm_on = Model.Alarm_on;
			Model.state = 'ConfigureState_Alarm';
			View.View = View.View_Configure_Alarm;
		},
		Exit: function () {
			Model.Alarm_hour = Model.configure_Alarm_hour;
			Model.Alarm_minute = Model.configure_Alarm_minute;
			Model.Alarm_on = Model.configure_Alarm_on;
		},
		Update(e) {
			if (e.type == "mouseup") {
				return;
			}
			switch (e.target.id) {
			case "mode": //进入正常状态
				Controller.FSM.ChangeState(NormalState);
				break;
			case "reset": //调节设置项
				Model.configure_Alarm++;
				if (3 == Model.configure_Alarm)
					Model.configure_Alarm = 0;
				break;
				break;
			case "start": //调节设置量
				switch (Model.configure_Alarm) {
				case 2: //hour
					Model.configure_Alarm_hour++;
					if (Model.configure_Alarm_hour == 24)
						Model.configure_Alarm_hour = 0;
					break;
				case 1: //minute
					Model.configure_Alarm_minute++;
					if (60 == Model.configure_Alarm_minute)
						Model.configure_Alarm_minute = 0;
					break;
				case 0: //Alarm_on
					Model.configure_Alarm_on = 1 - Model.configure_Alarm_on;
					break;
				}
				break;
			}
		}
	};
	//
	$("#light").mousedown(Controller.light);
	$("#light").mouseup(Controller.light);

	$("#mode").mousedown(Controller.click);
	$("#mode").mouseup(Controller.click);

	$("#reset").mousedown(Controller.click);
	$("#reset").mouseup(Controller.click);

	$("#start").mousedown(Controller.click);
	$("#start").mouseup(Controller.click);

	Controller.FSM = StateMachine;
	Controller.FSM.ChangeState(NormalState);
	Controller.timer = setInterval(function () {
			Model.add();
			View.View();
			View.View_Blink();
		}, 10);

});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和风化雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值