package order
import "fmt"
// State decides which actions are legal and returns the next state.
type State interface {
Name() string
Pay(o *Order) (State, error)
Ship(o *Order) (State, error)
Deliver(o *Order) (State, error)
Cancel(o *Order) (State, error)
}
// base rejects everything; concrete states embed it and override.
type base struct{ name string }1
func (b base) Name() string { return b.name }
func (b base) Pay(*Order) (State, error) { return nil, b.deny("pay") }
func (b base) Ship(*Order) (State, error) { return nil, b.deny("ship") }
func (b base) Deliver(*Order) (State, error) { return nil, b.deny("deliver") }
func (b base) Cancel(*Order) (State, error) { return nil, b.deny("cancel") }
func (b base) deny(action string) error {
return fmt.Errorf("cannot %s a %s order", action, b.name)
}
type pending struct{ base }2
type paid struct{ base }
type shipped struct{ base }
var (
Pending State = pending{base{"PENDING"}}3
Paid State = paid{base{"PAID"}}
Shipped State = shipped{base{"SHIPPED"}}
Delivered State = base{"DELIVERED"}
Cancelled State = base{"CANCELLED"}
)
func (pending) Pay(*Order) (State, error) { return Paid, nil }4
func (pending) Cancel(*Order) (State, error) { return Cancelled, nil }
func (paid) Ship(*Order) (State, error) { return Shipped, nil }
func (shipped) Deliver(*Order) (State, error) { return Delivered, nil }
func (paid) Cancel(o *Order) (State, error) {
o.refund()
return Cancelled, nil
}