UML课设

课题:

利用面向对象思维与Python语言,设计一个仿真系统
1.设计思路汇报
2.编程实现

系统名称:投币式饮料自助售卖机系统

Python代码实现

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
import os
import time
import tkinter as tk
from tkinter import messagebox, simpledialog

# 用户基类,包含共有属性和方法
class User:
total_time_spent = 0 # 记录所有用户的总耗时时间

def __init__(self, name):
# 初始化用户的名字
self.name = name

@classmethod
def add_time_spent(cls, time_spent):
# 类方法,用于累加操作的耗时
cls.total_time_spent += time_spent # 增加耗时时间
print(f"操作耗时:{time_spent}秒,累计耗时:{cls.total_time_spent}秒。")

def browse_drinks(self, vending_machine, time_spent=20):
# 用户浏览饮料的方法
vending_machine.browse_drinks() # 调用售卖机的浏览饮料方法
User.add_time_spent(time_spent) # 累加浏览饮料的耗时

# 顾客类,继承自用户类
class Customer(User):
def __init__(self, name, customer_id):
super().__init__(name) # 调用父类的构造方法初始化名字
self.customer_id = customer_id # 初始化顾客ID

def browse_drinks(self, vending_machine):
super().browse_drinks(vending_machine) # 调用父类的浏览饮料方法

def buy_drink(self, drink_name, coin_value, vending_machine, time_spent=5):
#顾客购买饮料的方法
if drink_name in vending_machine.drinks: # 检查饮料是否存在
drink = vending_machine.drinks[drink_name]
if drink.quantity > 0: # 检查库存
if coin_value >= drink.price: # 检查支付是否足够
change = coin_value - drink.price
if change == 0 or vending_machine.calculate_change(change): # 检查是否可以找零
drink.quantity -= 1 # 减少库存
vending_machine.save_drinks() # 保存饮料信息
vending_machine.save_transaction(coin_value) # 保存交易信息
User.add_time_spent(time_spent) # 记录耗时
if change > 0:
vending_machine.distribute_change(change) # 发放找零
return True, change # 返回成功和找零金额
else:
return True, 0 # 返回成功和0找零
else:
print("无法找零,请尝试其他面额的硬币。")
User.add_time_spent(time_spent)
return False, 0
else:
print("资金不足,请增加硬币数量。")
User.add_time_spent(time_spent)
return False, 0
else:
print("饮料缺货。")
User.add_time_spent(time_spent)
return False, 0
else:
print("未找到饮料。")
User.add_time_spent(time_spent)
return False, 0

# 管理员类,继承自用户类
class Admin(User):
def __init__(self, name, admin_id, password):
super().__init__(name) # 调用父类构造方法初始化名字
self.admin_id = admin_id # 初始化管理员ID
self.password = password # 初始化管理员密码

def login(self, admin_id, password, time_spent=3):
# 管理员登录
if self.admin_id == "admin" and self.password == "admin": # 验证管理员凭证
print("管理员登录成功。")
User.add_time_spent(time_spent) # 累加登录时间
return True
else:
print("管理员凭证无效。")
User.add_time_spent(time_spent) # 累加时间
return False

def replenish_drink(self, drink_name, quantity, price, vending_machine, time_spent=3):
# 管理员补充饮料
vending_machine.add_drink(Drink(drink_name, quantity, price)) # 将饮料添加到售卖机
vending_machine.save_drinks() # 保存饮料信息
print("补充饮料库存成功。")
User.add_time_spent(time_spent) # 累加时间

def replenish_change(self, coin_denomination, quantity, vending_machine, time_spent=2):
# 管理员补充找零硬币
if coin_denomination in vending_machine.coins:
vending_machine.coins[coin_denomination].set_total(
vending_machine.coins[coin_denomination].total + quantity) # 更新硬币数量
else:
vending_machine.add_coin(Coin(coin_denomination)) # 新增硬币面额
vending_machine.coins[coin_denomination].set_total(quantity) # 设置数量
print("补充找零硬币成功。")
User.add_time_spent(time_spent) # 累加时间

def collect_coins(self, vending_machine, time_spent=10):
# 提取硬币
collected_coins = vending_machine.collect_income_from_file() # 从文件收取硬币
vending_machine.delete_income_file() # 删除收入文件
print(f"已提取{collected_coins}元硬币。")
User.add_time_spent(time_spent) # 累加时间
return collected_coins

def set_drink_price(self, drink_name, price, vending_machine, time_spent=2):
# 设定饮料价格
if drink_name in vending_machine.drinks:
vending_machine.drinks[drink_name].set_price(price) # 设置饮料新价格
print(f"{drink_name}的价格已设定为{price}")
User.add_time_spent(time_spent) # 累加时间
return True # 返回True表示成功设置价格
else:
print("未找到饮料,无法设置价格。")
User.add_time_spent(time_spent) # 累加时间
return False # 返回False表示未找到饮料

# 饮料类,描述饮料的属性和行为
class Drink:
def __init__(self, name, quantity, price):
self.name = name # 饮料名称
self.quantity = quantity # 饮料数量
self.price = price # 饮料价格

def set_price(self, price):
# 设定饮料价格
self.price = price # 更新价格

def set_name(self, name):
# 设定饮料名称
self.name = name

def set_quantity(self, quantity):
# 设定饮料数量
self.quantity = quantity

# 硬币类,描述硬币的属性和行为
class Coin:
def __init__(self, denomination):
self.denomination = denomination # 硬币面额
self.total = 0 # 硬币数量

def set_denomination(self, denomination):
self.denomination = denomination # 设定硬币面额

def set_total(self, total):
self.total = total # 设定硬币数量

# 售卖机类,管理饮料、硬币以及收入
class VendingMachine:
def __init__(self):
self.drinks = {} # 饮料库存
self.coins = {} # 找零硬币数量
self.total_income = 0 # 总收入
self.load_drinks() # 加载饮料信息,读取文件中的饮料信息

def add_drink(self, drink):
# 添加饮料到库存
self.drinks[drink.name] = drink

def add_coin(self, coin):
# 添加找零硬币
if coin.denomination in self.coins:
self.coins[coin.denomination].total += 1
else:
self.coins[coin.denomination] = coin

def browse_drinks(self):
# 显示售卖机饮料中的饮料列表
drink_list = "\n".join([f"{name}: 库存{drink.quantity},价格:{drink.price}"
for name, drink in self.drinks.items()])
if not drink_list:
print("目前售卖机没有饮料。")
else:
print("目前可购买的饮料列表:")
print(drink_list)

def save_drinks(self):
# 将饮料信息保存到文件
with open('drinks.txt', 'w') as f:
for name, drink in self.drinks.items():
f.write(f"{name},{drink.quantity},{drink.price}\n")

def load_drinks(self):
# 从文件加载饮料信息
try:
with open('drinks.txt', 'r') as f:
for line in f:
name, quantity, price = line.strip().split(',')
self.add_drink(Drink(name, int(quantity), float(price)))
except FileNotFoundError:
print("目前售卖机没有饮料。")

def calculate_change(self, change):
# 计算找零
sorted_denominations = sorted(self.coins.keys(), reverse=True) # 按硬币面额降序排列
for denomination in sorted_denominations:
coins_to_give = min(int(change // denomination), self.coins[denomination].total)
if coins_to_give > 0:
self.coins[denomination].total -= coins_to_give
change -= coins_to_give * denomination
if change == 0:
return True
return False

def distribute_change(self, change):
# 分发找零硬币
sorted_denominations = sorted(self.coins.keys(), reverse=True)
for denomination in sorted_denominations:
coins_to_give = min(int(change // denomination), self.coins[denomination].total)
if coins_to_give > 0:
self.coins[denomination].total -= coins_to_give
change -= coins_to_give * denomination
print(f"发放面额 {denomination} 元的硬币 {coins_to_give} 枚")
return change == 0

def save_transaction(self, coin_value):
# 保存交易记录到文件
try:
with open('income.txt', 'a') as f:
f.write(f"{coin_value}\n")
self.total_income += coin_value
except Exception as e:
print(f"写入文件时发生错误:{e}")

def collect_income_from_file(self):
# 从文件计算收入总和
try:
with open('income.txt', 'r') as f:
income = sum(float(line.strip()) for line in f)
return income
except FileNotFoundError:
print("未查询到收入。")
return 0

def delete_income_file(self):
# 删除收入文件
try:
os.remove('income.txt')
print("当前将用户投入的所有硬币全部提取出来。")
except FileNotFoundError:
print("没有硬币可提取。")
except Exception as e:
print(f"删除文件时发生错误:{e}")

# 可视化界面部分
class GUI:
def __init__(self, master, vending_machine, customer, admin):
# 初始化图形界面的构造方法
self.master = master
self.master.title("投币式饮料自助售卖机系统")
self.vending_machine = vending_machine
self.customer = customer
self.admin = admin

# 创建窗口顶部的标题标签
title_label = tk.Label(master, text="投币式饮料自助售卖机系统", font=("Arial", 16, "bold"))
title_label.pack(pady=10) # 放置标题标签,并在垂直方向上添加外边距

# 创建操作按钮
self.browse_button = tk.Button(master, text="浏览饮料", command=self.browse_drinks)
self.browse_button.pack(pady=10)

self.buy_button = tk.Button(master, text="购买饮料", command=self.buy_drink)
self.buy_button.pack(pady=10)

self.admin_button = tk.Button(master, text="管理员登录", command=self.admin_login)
self.admin_button.pack(pady=10)

self.quit_button = tk.Button(master, text="退出", command=master.quit)
self.quit_button.pack(pady=10)

def browse_drinks(self):
start_time = time.time() # 记录开始时间
drink_list = ""
for name, drink in self.vending_machine.drinks.items():
drink_list += f"{name}: 库存{drink.quantity},价格:{drink.price}\n"

if not drink_list:
drink_list = "目前售卖机没有饮料。"

messagebox.showinfo("浏览饮料", drink_list)
end_time = time.time() # 记录结束时间
elapsed_time = end_time - start_time
elapsed_time = round(elapsed_time)
User.add_time_spent(elapsed_time)

def buy_drink(self):
drink_name = simpledialog.askstring("购买饮料", "请输入饮料名称:")
coin_value = simpledialog.askfloat("购买饮料", "请输入投入硬币的金额:")

success, change = self.customer.buy_drink(drink_name, coin_value, self.vending_machine)
if success:
if change > 0:
messagebox.showinfo("购买成功", f"购买成功!发放找零:{change}元。")
else:
messagebox.showinfo("购买成功", "购买成功!不需要找零。")
else:
messagebox.showerror("购买失败", "购买失败,请检查饮料是否有货或硬币金额是否足够。")

def admin_login(self):
# 管理员登录处理
login_window = tk.Toplevel(self.master)
login_window.title("管理员登录")

tk.Label(login_window, text="管理员ID:").pack(pady=5)
admin_id = tk.Entry(login_window)
admin_id.pack(pady=5)

tk.Label(login_window, text="管理员密码:").pack(pady=5)
password = tk.Entry(login_window, show="*")
password.pack(pady=5)

login_button = tk.Button(login_window, text="登录",
command=lambda: self.admin_actions(admin_id.get(), password.get()))
login_button.pack(pady=10)

def admin_actions(self, admin_id, password):
if self.admin.login(admin_id, password):
self.admin_menu()
else:
messagebox.showerror("登录失败", "管理员凭证无效,请重试。")

def admin_menu(self):
# 管理员操作菜单
menu_window = tk.Toplevel(self.master)
menu_window.title("管理员操作")

replenish_drinks_button = tk.Button(menu_window, text="补充饮料", command=self.replenish_drinks)
replenish_drinks_button.pack(pady=10)

batch_import_button = tk.Button(menu_window, text="批量补充饮料", command=self.batch_import_drinks)
batch_import_button.pack(pady=10)

replenish_change_button = tk.Button(menu_window, text="补充找零硬币", command=self.replenish_change)
replenish_change_button.pack(pady=10)

collect_coins_button = tk.Button(menu_window, text="提取硬币", command=self.collect_coins)
collect_coins_button.pack(pady=10)

set_price_button = tk.Button(menu_window, text="设定饮料价格", command=self.set_drink_price)
set_price_button.pack(pady=10)

logout_button = tk.Button(menu_window, text="注销", command=menu_window.destroy)
logout_button.pack(pady=10)

def replenish_drinks(self):
# 补充饮料的功能
drink_name = simpledialog.askstring("补充饮料", "请输入饮料名称:")
if drink_name: # 检查用户是否输入了饮料名称
quantity = simpledialog.askinteger("补充饮料", "请输入补充数量:")
if quantity is not None: # 检查用户是否输入了数量
price = simpledialog.askfloat("补充饮料", "请输入饮料价格:")
if price is not None: # 检查用户是否输入了价格
self.admin.replenish_drink(drink_name, quantity, price, self.vending_machine)
messagebox.showinfo("补充成功", "饮料库存补充成功!")
self.vending_machine.save_drinks() # 保存饮料信息
else:
messagebox.showwarning("补充失败", "请输入有效的饮料价格。")
else:
messagebox.showwarning("补充失败", "请输入有效的补充数量。")
else:
messagebox.showwarning("补充失败", "请输入饮料名称。")

def batch_import_drinks(self):
# 批量补充饮料的功能
start_time = time.time() # 记录开始时间
import_window = tk.Toplevel(self.master)
import_window.title("批量补充饮料")

tk.Label(import_window, text="请输入饮料数据(格式:名称,数量,价格):").pack(pady=5)
text_area = tk.Text(import_window, height=10, width=50)
text_area.pack(pady=5)
import_button = tk.Button(import_window, text="补充", command=lambda: self.import_drinks(text_area.get("1.0", tk.END), start_time))
import_button.pack(pady=10)

def import_drinks(self, data, start_time):
# 处理批量补充饮料数据
lines = data.strip().split("\n")
success_count = 0
fail_count = 0

for line in lines:
try:
name, quantity, price = line.split(",")
quantity = int(quantity)
price = float(price)
self.admin.replenish_drink(name, quantity, price, self.vending_machine)
success_count += 1
except ValueError:
fail_count += 1
print(f"格式错误或数据转换失败:{line}")

end_time = time.time() # 记录结束时间
elapsed_time = end_time - start_time
elapsed_time = round(elapsed_time)
User.add_time_spent(elapsed_time)

if success_count > 0:
self.vending_machine.save_drinks()
messagebox.showinfo("批量补充成功", f"成功导入{success_count}条数据。")
if fail_count > 0:
messagebox.showwarning("批量补充失败", f"{fail_count}条数据格式错误或转换失败。请检查输入格式。")

def replenish_change(self):
# 补充找零硬币的功能
coin_denomination = simpledialog.askinteger("补充硬币", "请输入硬币面额:")
if coin_denomination is not None: # 检查用户是否输入了硬币面额
quantity = simpledialog.askinteger("补充硬币", "请输入补充数量:")
if quantity is not None: # 检查用户是否输入了数量
self.admin.replenish_change(coin_denomination, quantity, self.vending_machine)
messagebox.showinfo("补充成功", "找零硬币补充成功!")
self.vending_machine.save_drinks() # 保存找零硬币信息
else:
messagebox.showwarning("取消操作", "未输入数量,操作已取消。")
else:
messagebox.showwarning("取消操作", "未输入硬币面额,操作已取消。")

def collect_coins(self):
# 提取硬币的功能
collected_coins = self.admin.collect_coins(self.vending_machine)
if collected_coins is not None:
message = f"硬币提取成功!共提取{collected_coins}元硬币。"
messagebox.showinfo("提取成功", message)
else:
messagebox.showinfo("提取成功", "没有硬币可提取。")

def set_drink_price(self):
# 设置饮料价格的功能
drink_name = simpledialog.askstring("设定价格", "请输入饮料名称:")
if drink_name: # 检查用户是否输入了饮料名称
price = simpledialog.askfloat("设定价格", "请输入新价格:")
if price is not None: # 检查用户是否输入了价格
if not self.admin.set_drink_price(drink_name, price, self.vending_machine):
messagebox.showwarning("设置失败", "未找到饮料,无法设置价格。")
else:
messagebox.showwarning("设置失败", "请输入有效的价格。")
else:
messagebox.showwarning("设置失败", "请输入饮料名称。")
# 主程序,创建应用并启动
def run_vending_machine_gui():
# 初始化各个对象
vending_machine = VendingMachine()
customer = Customer("用户", "user")
admin = Admin("admin", "admin", "admin")

root = tk.Tk()
root.geometry("600x400") # 设置窗口大小
app = GUI(root, vending_machine, customer, admin)

# 初始化饮料和找零硬币
admin.replenish_drink("可乐", 10, 3.0, vending_machine, time_spent=3)
admin.replenish_drink("雪碧", 15, 3.0, vending_machine, time_spent=3)
admin.replenish_drink("矿泉水", 20, 2.0, vending_machine, time_spent=3)
admin.replenish_change(1.0, 1000, vending_machine, time_spent=2)

root.mainloop()

if __name__ == "__main__":
run_vending_machine_gui()
# 投币式饮料自助售卖机系统程序说明:
# 1.程序运行之后会有一个可视化的界面弹窗用来进行交互
# 2.系统是基于时间的,每一个操作都设置了具体时间消耗,会在执行之后在控制台打印出来
# 3.程序开始运行后,会先进行补充饮料和找零硬币的初始化
# 4.管理员登录操作的账号是admin,密码是admin
# 5.顾客投入的硬币数据通过写入新建的文本文件(.txt)来存储
# 6.管理员补充的饮料相关数据通过写入新建的文本文件(.txt)来存储
# 7.管理员提取硬币操作提取的是顾客投入的硬币,不提取找零硬币
# 8.管理员能够对饮料数据进行批量补充

UML课设
http://blog.hrseno.cn/2024/11/17/UML课设/
作者
黄浩森
发布于
2024年11月17日
许可协议