欢迎光临
我们一直在努力

OOD的展现

外卖点餐自取系统 — OOD 设计文档


一、关键场景

场景1:顾客浏览菜品并下单

步骤角色操作涉及类
1 顾客 输入手机号密码登录 LoginFrame, UserService, UserRepository
2 系统 验证身份,判断为 Customer User, Customer
3 顾客 浏览菜品列表 ProductPanel, ProductService, ProductRepository
4 顾客 搜索"面" ProductService.searchProducts()
5 顾客 双击"红烧牛肉面"加购 CartService.addToCart()
6 顾客 查看购物车 CartPanel, CartService
7 顾客 点击提交订单 OrderService.placeOrder()
8 系统 加锁→查库存→扣库存→生成订单→清空购物车 synchronized(lock)
9 顾客 查看订单,支付 OrderPanel, OrderService.payOrder()

场景2:管理员接单并完成订单

步骤角色操作涉及类
1 管理员 输入手机号密码登录 LoginFrame, UserService
2 系统 验证身份,判断为 Admin User, Admin
3 管理员 查看待接单订单 AdminFrame, AdminService.getPendingOrders()
4 管理员 选中订单,点击接单 AdminService.acceptOrder()
5 系统 状态变更为"备餐中" Order.setStatus(COOKING)
6 管理员 点击备餐完成 AdminService.readForPickup()
7 系统 生成取餐码,状态→待自取 IdGenerator.generatePickupCode()
8 管理员 确认顾客取餐 AdminService.completeOrder()
9 系统 状态→已完成 Order.setStatus(COMPLETED)

二、架构设计(MVC 分层)

层包职责对应 MVC
表现层 view Swing 窗口和面板,处理用户交互 View
业务逻辑层 service 核心业务流程、校验、状态控制 Controller
数据访问层 repository 数据存取(HashMap 模拟数据库) Model
实体层 model 数据模型 + 枚举 + 状态机 Model

调用规则:view → service → repository → model,单向依赖,不可跨层调用。


三、核心类清单(含属性、方法、可见性、关系)

类包属性(可见性)方法(可见性)继承/关联
User model #userId:String, #phone:String, #password:String +getUserId():String, +getPhone():String, +getPassword():String 父类
Customer model (继承) extends User
Admin model (继承) extends User
Product model -productId:String, -name:String, -stock:int, -price:double, -category:String +getPrice():double, +getStock():int, +setStock(int):void
Order model -orderId:String, -total:double, -status:OrderStatusEnum, -pickupcode:String, -date:Date, -orderItems:List<OrderItem>, -userId:String +calculateTotal():double, +getStatus():OrderStatusEnum, +getOrderItems():List 1…* → OrderItem
OrderItem model -productId:String, -quantity:int, -price:double, -name:String +getPrice():double, +getQuantity():int, +getName():String 快照关联 → Product
ShoppingCart model -cartItems:List<CartItem> +addToCartItem(String,int):void, +removeFromCartItem(String):void 0…* → CartItem
CartItem model -productId:String, -quantity:int +getProductId():String, +getQuantity():int 关联 → Product
OrderStatusEnum model PENDING_PAYMENT, PENDING_ACCEPT, COOKING, READY_FOR_PICKUP, COMPLETED, CANCELLED +canTransitionTo(OrderStatusEnum):boolean, +getDescription():String, +nextAfterPay():OrderStatusEnum
UserService service -userRepository:UserRepository +register(String,String,String):User, +login(String,String):User, +isAdmin(String):boolean
ProductService service -productRepository:ProductRepository +getAllProducts():List, +searchProducts(String):List, +addProduct(…):Product, +updateProduct(…):void, +deleteProduct(String):void
CartService service -shoppingCartRepository:ShoppingCartRepository, -productRepository:ProductRepository +getCart(String):ShoppingCart, +addToCart(String,String,int):void, +removeFromCart(String,String):void, +getTotal(String):double, +clearCart(String):void, +isCartEmpty(String):boolean
OrderService service -orderRepository:OrderRepository, -productRepository:ProductRepository, -shoppingCartRepository:ShoppingCartRepository, -lock:Object +placeOrder(String):Order, +payOrder(String):void, +cancelOrder(String):void, +getUserOrders(String):List, +getOrderById(String):Order
AdminService service -orderRepository:OrderRepository, -productRepository:ProductRepository, -productService:ProductService +getAllOrders():List, +getPendingOrders():List, +getCookingOrders():List, +acceptOrder(String):void, +rejectOrder(String):void, +readForPickup(String):void, +completeOrder(String):void
UserRepository repository -userMap:Map<String,User> +save(User):void, +findById(String):User, +findByPhone(String):User, +existByPhone(String):boolean, +findAll():List
ProductRepository repository -productMap:Map<String,Product> +save(Product):void, +findProductById(String):Product, +findAll():List, +findByCategory(String):List, +searchByName(String):List, +reduceStock(String,int):void, +updateStock(String,int):void
OrderRepository repository -orderMap:Map<String,Order> +save(Order):void, +findOrderById(String):Order, +findAllOrders():List, +findAllOrdersByUserId(String):List, +findAllOrdersByStatus(OrderStatusEnum):List
ShoppingCartRepository repository -shoppingCartMap:Map<String,ShoppingCart> +findByUserId(String):ShoppingCart, +save(String,ShoppingCart):void, +clear(String):void, +remove(String):void
LoginFrame view -userService, -cartService, -orderService, -productService, -adminService, -phoneField, -passwordField 登录验证+路由分发
RegisterFrame view -userService, -phoneField, -passwordField, -roleBox 注册新用户
CustomerFrame view -user, -cartService, -orderService, -productService, -userService 组装 ProductPanel+CartPanel+OrderPanel
AdminFrame view -adminService, -userService, -cartService, -orderService, -productService 订单管理+菜品管理
ProductPanel view -productService, -cartService, -userId +refreshData():void
CartPanel view -cartService, -productService, -userId +refreshData():void
OrderPanel view -orderService, -userId +refreshData():void
AddProductDialog view -productService 添加菜品弹窗
UpdateProductDialog view -productService 更新菜品弹窗
OrderItemDialog view 显示订单项明细
IdGenerator util -userCounter:int, -productCounter:int, -orderCounter:int (static) +generateUserId():String, +generateProductId():String, +generateOrderId():String, +generatePickupCode():String
Validator util +isVailPhone(String):boolean, +isVailPassword(String):boolean, +isVailQuantity(int):boolean
BusinessException exception extends RuntimeException
InsufficientStockException exception extends BusinessException
UnauthorizedException exception extends BusinessException

四、继承关系

RuntimeException
└── BusinessException
├── InsufficientStockException
└── UnauthorizedException

User
├── Customer
└── Admin

JFrame
├── LoginFrame
├── RegisterFrame
├── CustomerFrame
└── AdminFrame

JPanel
├── ProductPanel
├── CartPanel
└── OrderPanel

JDialog
├── AddProductDialog
├── UpdateProductDialog
└── OrderItemDialog

text


五、关联关系(概念类图 + 代码实现)

下图展示了系统中核心类之间的关联关系,包括一对一、一对多,以及快照关联。

#mermaid-svg-fwVnTrBmwPT9enu6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fwVnTrBmwPT9enu6 .error-icon{fill:#552222;}#mermaid-svg-fwVnTrBmwPT9enu6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fwVnTrBmwPT9enu6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fwVnTrBmwPT9enu6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fwVnTrBmwPT9enu6 .marker.cross{stroke:#333333;}#mermaid-svg-fwVnTrBmwPT9enu6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fwVnTrBmwPT9enu6 p{margin:0;}#mermaid-svg-fwVnTrBmwPT9enu6 g.classGroup text{fill:#9370DB;stroke:none;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-fwVnTrBmwPT9enu6 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-fwVnTrBmwPT9enu6 .cluster-label text{fill:#333;}#mermaid-svg-fwVnTrBmwPT9enu6 .cluster-label span{color:#333;}#mermaid-svg-fwVnTrBmwPT9enu6 .cluster-label span p{background-color:transparent;}#mermaid-svg-fwVnTrBmwPT9enu6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fwVnTrBmwPT9enu6 .cluster text{fill:#333;}#mermaid-svg-fwVnTrBmwPT9enu6 .cluster span{color:#333;}#mermaid-svg-fwVnTrBmwPT9enu6 .nodeLabel,#mermaid-svg-fwVnTrBmwPT9enu6 .edgeLabel{color:#131300;}#mermaid-svg-fwVnTrBmwPT9enu6 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-fwVnTrBmwPT9enu6 .label text{fill:#131300;}#mermaid-svg-fwVnTrBmwPT9enu6 .labelBkg{background:#ECECFF;}#mermaid-svg-fwVnTrBmwPT9enu6 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-fwVnTrBmwPT9enu6 .classTitle{font-weight:bolder;}#mermaid-svg-fwVnTrBmwPT9enu6 .node rect,#mermaid-svg-fwVnTrBmwPT9enu6 .node circle,#mermaid-svg-fwVnTrBmwPT9enu6 .node ellipse,#mermaid-svg-fwVnTrBmwPT9enu6 .node polygon,#mermaid-svg-fwVnTrBmwPT9enu6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fwVnTrBmwPT9enu6 .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 g.clickable{cursor:pointer;}#mermaid-svg-fwVnTrBmwPT9enu6 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-fwVnTrBmwPT9enu6 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-fwVnTrBmwPT9enu6 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-fwVnTrBmwPT9enu6 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-fwVnTrBmwPT9enu6 .dashed-line{stroke-dasharray:3;}#mermaid-svg-fwVnTrBmwPT9enu6 .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-fwVnTrBmwPT9enu6 #compositionStart,#mermaid-svg-fwVnTrBmwPT9enu6 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #compositionEnd,#mermaid-svg-fwVnTrBmwPT9enu6 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #dependencyStart,#mermaid-svg-fwVnTrBmwPT9enu6 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #dependencyStart,#mermaid-svg-fwVnTrBmwPT9enu6 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #extensionStart,#mermaid-svg-fwVnTrBmwPT9enu6 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #extensionEnd,#mermaid-svg-fwVnTrBmwPT9enu6 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #aggregationStart,#mermaid-svg-fwVnTrBmwPT9enu6 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #aggregationEnd,#mermaid-svg-fwVnTrBmwPT9enu6 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #lollipopStart,#mermaid-svg-fwVnTrBmwPT9enu6 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 #lollipopEnd,#mermaid-svg-fwVnTrBmwPT9enu6 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fwVnTrBmwPT9enu6 .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-fwVnTrBmwPT9enu6 .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fwVnTrBmwPT9enu6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fwVnTrBmwPT9enu6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fwVnTrBmwPT9enu6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

拥有

拥有

包含

快照关联

包含

关联

使用

1

1

1

*

1

*

1

0..*

1..*

1

0..*

1

User

+String userId

+String phone

+String password

«extends User»

Customer

«extends User»

Admin

Product

+String productId

+String name

+int stock

+double price

+String category

Order

+String orderId

+double total

+OrderStatusEnum status

+String pickupcode

+Date date

+String userId

OrderItem

+String productId

+int quantity

+double price

+String name

ShoppingCart

+List cartItems

CartItem

+String productId

+int quantity

«enumeration»

OrderStatusEnum

PENDING_PAYMENT

PENDING_ACCEPT

COOKING

READY_FOR_PICKUP

COMPLETED

CANCELLED

代码实现方式:

关联实现
User → ShoppingCart ShoppingCartRepository 以 userId 为 key
User → Order Order 存 userId,OrderRepository.findByUserId()
Order → OrderItem Order 存 List<OrderItem>
OrderItem → Product OrderItem 存 productId、快照 price 和 name
ShoppingCart → CartItem ShoppingCart 存 List<CartItem>
CartItem → Product CartItem 存 productId

六、状态图(订单状态流转)

订单状态流转图(状态图)

系统内订单共有 6 种状态,状态之间的流转由 OrderStatusEnum.canTransitionTo() 方法严格控制。

#mermaid-svg-UGzbcS48krsWXC8l{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UGzbcS48krsWXC8l .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UGzbcS48krsWXC8l .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UGzbcS48krsWXC8l .error-icon{fill:#552222;}#mermaid-svg-UGzbcS48krsWXC8l .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UGzbcS48krsWXC8l .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UGzbcS48krsWXC8l .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UGzbcS48krsWXC8l .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UGzbcS48krsWXC8l .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UGzbcS48krsWXC8l .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UGzbcS48krsWXC8l .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UGzbcS48krsWXC8l .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UGzbcS48krsWXC8l .marker.cross{stroke:#333333;}#mermaid-svg-UGzbcS48krsWXC8l svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UGzbcS48krsWXC8l p{margin:0;}#mermaid-svg-UGzbcS48krsWXC8l defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-UGzbcS48krsWXC8l g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-UGzbcS48krsWXC8l g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-UGzbcS48krsWXC8l g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-UGzbcS48krsWXC8l g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-UGzbcS48krsWXC8l g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-UGzbcS48krsWXC8l .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-UGzbcS48krsWXC8l .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-UGzbcS48krsWXC8l .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-UGzbcS48krsWXC8l .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UGzbcS48krsWXC8l .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-UGzbcS48krsWXC8l .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-UGzbcS48krsWXC8l .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-UGzbcS48krsWXC8l .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UGzbcS48krsWXC8l .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UGzbcS48krsWXC8l .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UGzbcS48krsWXC8l .edgeLabel .label text{fill:#333;}#mermaid-svg-UGzbcS48krsWXC8l .label div .edgeLabel{color:#333;}#mermaid-svg-UGzbcS48krsWXC8l .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-UGzbcS48krsWXC8l .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-UGzbcS48krsWXC8l .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-UGzbcS48krsWXC8l .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-UGzbcS48krsWXC8l .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-UGzbcS48krsWXC8l .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UGzbcS48krsWXC8l .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UGzbcS48krsWXC8l #statediagram-barbEnd{fill:#333333;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UGzbcS48krsWXC8l .cluster-label,#mermaid-svg-UGzbcS48krsWXC8l .nodeLabel{color:#131300;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-UGzbcS48krsWXC8l .note-edge{stroke-dasharray:5;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-note text{fill:black;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram-note .nodeLabel{color:black;}#mermaid-svg-UGzbcS48krsWXC8l .statediagram .edgeLabel{color:red;}#mermaid-svg-UGzbcS48krsWXC8l #dependencyStart,#mermaid-svg-UGzbcS48krsWXC8l #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-UGzbcS48krsWXC8l .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UGzbcS48krsWXC8l :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

创建订单

支付成功

取消订单

商家接单

商家拒单

备餐完成 / 生成取餐码

确认取餐

PENDING_PAYMENT

PENDING_ACCEPT

CANCELLED

COOKING

READY_FOR_PICKUP

COMPLETED

代码实现:OrderStatusEnum.canTransitionTo(OrderStatusEnum) 控制合法流转。


七、时序图(顾客下单)

OrderRepoOrderServiceCartRepoProductRepoCartServiceProductPanelCustomerFrameUserRepoUserServiceLoginFrameOrderRepoOrderServiceCartRepoProductRepoCartServiceProductPanelCustomerFrameUserRepoUserServiceLoginFrame#mermaid-svg-K8Rw9fulrdrBQgtP{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-K8Rw9fulrdrBQgtP .error-icon{fill:#552222;}#mermaid-svg-K8Rw9fulrdrBQgtP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-K8Rw9fulrdrBQgtP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-K8Rw9fulrdrBQgtP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-K8Rw9fulrdrBQgtP .marker.cross{stroke:#333333;}#mermaid-svg-K8Rw9fulrdrBQgtP svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-K8Rw9fulrdrBQgtP p{margin:0;}#mermaid-svg-K8Rw9fulrdrBQgtP .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-K8Rw9fulrdrBQgtP text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-K8Rw9fulrdrBQgtP .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-K8Rw9fulrdrBQgtP .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-K8Rw9fulrdrBQgtP #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-K8Rw9fulrdrBQgtP .sequenceNumber{fill:white;}#mermaid-svg-K8Rw9fulrdrBQgtP #sequencenumber{fill:#333;}#mermaid-svg-K8Rw9fulrdrBQgtP #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-K8Rw9fulrdrBQgtP .messageText{fill:#333;stroke:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-K8Rw9fulrdrBQgtP .labelText,#mermaid-svg-K8Rw9fulrdrBQgtP .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .loopText,#mermaid-svg-K8Rw9fulrdrBQgtP .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-K8Rw9fulrdrBQgtP .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-K8Rw9fulrdrBQgtP .noteText,#mermaid-svg-K8Rw9fulrdrBQgtP .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-K8Rw9fulrdrBQgtP .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-K8Rw9fulrdrBQgtP .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-K8Rw9fulrdrBQgtP .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-K8Rw9fulrdrBQgtP .actorPopupMenu{position:absolute;}#mermaid-svg-K8Rw9fulrdrBQgtP .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-K8Rw9fulrdrBQgtP .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-K8Rw9fulrdrBQgtP .actor-man circle,#mermaid-svg-K8Rw9fulrdrBQgtP line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-K8Rw9fulrdrBQgtP :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}critical[同步锁 synchronized(lock)]顾客输入手机号、密码login(phone, password)findByPhone(phone)UserUser (Customer)new CustomerFrame(user, …)登录成功,显示顾客界面双击菜品(红烧牛肉面)弹出输入框,输入数量 2addToCart(userId, productId, 2)findProductById(productId)Product (name="红烧牛肉面", stock=50)校验库存 (50 >= 2)addToCartItem / savevoid提示"已添加到购物车"点击"提交订单"placeOrder(userId)findByUserId(userId)ShoppingCart (含红烧牛肉面 x2)findProductById (遍历)检查所有商品库存是否充足reduceStock (遍历扣减)save(order)clear(userId)Order (orderId=ORDxxx, total=¥30.00)下单成功,显示订单号顾客


八、时序图(管理员接单)

OrderOrderRepoAdminServiceAdminFrameOrderOrderRepoAdminServiceAdminFrame#mermaid-svg-9cUeeOEnvo2hLy1B{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9cUeeOEnvo2hLy1B .error-icon{fill:#552222;}#mermaid-svg-9cUeeOEnvo2hLy1B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9cUeeOEnvo2hLy1B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9cUeeOEnvo2hLy1B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9cUeeOEnvo2hLy1B .marker.cross{stroke:#333333;}#mermaid-svg-9cUeeOEnvo2hLy1B svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9cUeeOEnvo2hLy1B p{margin:0;}#mermaid-svg-9cUeeOEnvo2hLy1B .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9cUeeOEnvo2hLy1B text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-9cUeeOEnvo2hLy1B .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-9cUeeOEnvo2hLy1B .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-9cUeeOEnvo2hLy1B #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-9cUeeOEnvo2hLy1B .sequenceNumber{fill:white;}#mermaid-svg-9cUeeOEnvo2hLy1B #sequencenumber{fill:#333;}#mermaid-svg-9cUeeOEnvo2hLy1B #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-9cUeeOEnvo2hLy1B .messageText{fill:#333;stroke:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9cUeeOEnvo2hLy1B .labelText,#mermaid-svg-9cUeeOEnvo2hLy1B .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .loopText,#mermaid-svg-9cUeeOEnvo2hLy1B .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-9cUeeOEnvo2hLy1B .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-9cUeeOEnvo2hLy1B .noteText,#mermaid-svg-9cUeeOEnvo2hLy1B .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-9cUeeOEnvo2hLy1B .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9cUeeOEnvo2hLy1B .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9cUeeOEnvo2hLy1B .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9cUeeOEnvo2hLy1B .actorPopupMenu{position:absolute;}#mermaid-svg-9cUeeOEnvo2hLy1B .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-9cUeeOEnvo2hLy1B .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9cUeeOEnvo2hLy1B .actor-man circle,#mermaid-svg-9cUeeOEnvo2hLy1B line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-9cUeeOEnvo2hLy1B :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}管理员点击"只看待接单"getPendingOrders()findAllOrdersByStatus(PENDING_ACCEPT)List Order待接单订单列表表格显示待接单订单选中订单,点击"接单"acceptOrder(orderId)findOrderById(orderId)Order校验状态是否为 PENDING_ACCEPTsetStatus(COOKING)save(order)void弹窗"已接单",刷新列表点击"备餐完成"readForPickup(orderId)findOrderById(orderId)Order校验状态是否为 COOKING生成取餐码 generatePickupCode()setPickupcode("4729")setStatus(READY_FOR_PICKUP)save(order)void弹窗"备餐完成,取餐码:4729"点击"确认取餐"completeOrder(orderId)findOrderById(orderId)Order校验状态是否为 READY_FOR_PICKUPsetStatus(COMPLETED)save(order)void弹窗"订单完成"管理员


九、数据库设计(HashMap 模拟)

表主键字段外键
User userId (String) phone, password
Product productId (String) name, stock, price, category
Order orderId (String) total, status, pickupcode, date, userId userId → User
OrderItem (嵌入 Order) productId, quantity, price, name productId → Product
ShoppingCart userId (String) cartItems: List<CartItem> userId → User
CartItem (嵌入 ShoppingCart) productId, quantity productId → Product

存储方式:HashMap<String, Entity>,key 为实体唯一标识,O(1) 查询。


十、设计模式应用

模式位置说明
状态模式 OrderStatusEnum 6种订单状态 + canTransitionTo() 控制流转
依赖注入 所有 Service 构造器 Repository 通过构造器传入,不内部 new
MVC 整体架构 view=View, service=Controller, model=Model
多态 User/Customer/Admin instanceof 判断角色,父类引用指向子类对象
单例思想 OrderService.lock private final Object lock 全局唯一锁对象

赞(0)
未经允许不得转载:171主机测评 » OOD的展现
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址