接口
接口:是一组行为的抽象,尽量用接口,以实现面向接口编程
当一个类型实现了接口中所有方法,就视为实现了该接口,无需显式声明
package main
import "fmt"
type Payment interface { // Pay 支付 Pay(amount float64) (string, error) // Refund 退款 Refund(transactionID string, amount float64) (string, error) // Query 查询 Query(transactionID string) (string, error)}
type Alipay struct { AppID string}
func (a *Alipay) Pay(amount float64) (string, error) { return fmt.Sprintf("pay %f with alipay\n", amount), nil}
func (a *Alipay) Refund(transactionID string, amount float64) (string, error) { return fmt.Sprintf("refund %s with alipay\n", transactionID), nil}
func (a *Alipay) Query(transactionID string) (string, error) { return fmt.Sprintf("query %s with alipay\n", transactionID), nil}
type Wechatpay struct { AppID string}
func (w *Wechatpay) Pay(amount float64) (string, error) { return fmt.Sprintf("pay %f with wechatpay\n", amount), nil}
func (w *Wechatpay) Refund(transactionID string, amount float64) (string, error) { return fmt.Sprintf("refund %s with wechatpay\n", transactionID), nil}
func (w *Wechatpay) Query(transactionID string) (string, error) { return fmt.Sprintf("query %s with wechatpay\n", transactionID), nil}
// 抽象: 多态的体现func ProcessPayment(p Payment, amount float64) (string, error) { fmt.Println("开始处理支付请求...") payStr, err := p.Pay(amount) if err != nil { return "", err } fmt.Printf("支付成功,交易金额为: %s", payStr) return payStr, nil}
func main() { alipay := &Alipay{ AppID: "123", }
wechatpay := &Wechatpay{ AppID: "456", }
transcations := []struct { Payment Payment Amount float64 Name string }{ {alipay, 100, "alipay"}, {wechatpay, 100, "wechatpay"}, }
for _, transcation := range transcations { payStr, err := ProcessPayment(transcation.Payment, transcation.Amount) if err != nil { fmt.Printf("支付失败,错误信息为: %s\n", err.Error()) continue } fmt.Printf("ProcessPayment 支付成功,交易编号为: %s\n", payStr) }}package main
import ( "encoding/json" "io" "net/http")
// 定义接口// 语法:type name interface{}type Server interface { Route(pattern string, handlerFunc http.HandlerFunc) Start(address string) error}
// 结构体如何实现接口// 当一个结构体具备接口的所有的方法的时候,它就实现了这个接口type sdkHttpServer struct { Name string}
// Route 注册路由func (s *sdkHttpServer) Route(pattern string, handlerFunc http.HandlerFunc) { http.HandleFunc(pattern, handlerFunc)}
// Start 启动服务func (s *sdkHttpServer) Start(address string) error { return http.ListenAndServe(address, nil)}
func NewHttpServer(name string) Server { return &sdkHttpServer{ Name: name, }}
// sync context 抽象// TODO 思考:这里为什么不选择interface,而选择structtype Context struct { Write http.ResponseWriter request *http.Request}
func (c *Context) ReadJson(data interface{}) error { // 读取data body, err := io.ReadAll(c.request.Body) if err != nil { // 要返回掉,不然会继续执行后面的代码 return err } // 反序列化 err = json.Unmarshal(body, data) if err != nil { return err } return nil}
func (c *Context) WriteJson(code int, data interface{}) error { c.Write.WriteHeader(code) respJson, err := json.Marshal(data) if err != nil { return err } _, err = c.Write.Write(respJson) return err}
func (c *Context) SuccessJson(data interface{}) error { return c.WriteJson(http.StatusOK, data)}
func (c *Context) BadRequestJson(data interface{}) error { return c.WriteJson(http.StatusBadRequest, data)}
func (c *Context) ServerErrorJson(data interface{}) error { return c.WriteJson(http.StatusInternalServerError, data)}
func home(writer http.ResponseWriter, request *http.Request) { ctx := &Context{ Write: writer, request: request, } err := ctx.ReadJson(request) if err != nil { // TODO return }
err = ctx.WriteJson(http.StatusOK, map[string]interface{}{ "code": 200, "message": "success", "data": request.URL.Path, }) if err != nil { // TODO 写入日志 }}
func main() { server := NewHttpServer("my-server") server.Route("/", home) server.Start(":8080")}空接口interface{}不包含任何方法,可以存储任意类型的值,类似于TypeScript中的any
package main
import "fmt"
func processEmptyInterface(i interface{}) { // 类型断言 switch v := i.(type) { case int: fmt.Println("int", v) case string: str := i.(string) fmt.Println("string", str) default: fmt.Println("unknown", v) }}
func main() { var anything interface{} processEmptyInterface(anything) // unknown <nil> anything = 123 processEmptyInterface(anything) // int 123 anything = "hello" processEmptyInterface(anything) // string hello}package main
import ( "fmt" "time")
type BaseUser struct { ID int UserName string Email string CreatedAt time.Time}
func (b BaseUser) GetCreateDate() string { return b.CreatedAt.Format(time.DateTime)}
func (b BaseUser) DisplayBasicInfo() { fmt.Printf("用户ID: %d, 用户名: %s, 邮箱: %s, 创建时间: %s\n", b.ID, b.UserName, b.Email, b.GetCreateDate())}
type Address struct { Province string City string Street string Detail string}
func (a Address) GetFullAddress() string { return fmt.Sprintf("%s,%s,%s,%s\n", a.Province, a.City, a.Street, a.Detail)}
type NormalUser struct { BaseUser Address []Address}
func (nu *NormalUser) AddAddress(address Address) { nu.Address = append(nu.Address, address)}
type VipUser struct { BaseUser Address []Address VipLevel int Discount float64 ExpireDate time.Time}
func (v VipUser) IsValid() bool { return time.Now().Before(v.ExpireDate)}
func (v VipUser) GetDiscount() float64 { if v.IsValid() { return v.Discount } return 1.0}
type UserService struct {}
const ( UserTypeNormal = "normal" UserTypeVip = "vip")
func generateUserID() int { return int(time.Now().Unix())}
func (s *UserService) CreateUser(username, email, userType string) (user interface{}, err error) { baseUser := BaseUser{ ID: generateUserID(), UserName: username, Email: email, CreatedAt: time.Now(), }
switch userType { case UserTypeNormal: normalUser := NormalUser{ BaseUser: baseUser, Address: []Address{}, } return normalUser, nil case UserTypeVip: vipUser := VipUser{ BaseUser: baseUser, VipLevel: 1, Discount: 0.9, ExpireDate: time.Now().AddDate(0, 0, 30), } return vipUser, nil default: return nil, fmt.Errorf("invalid user type: %s", userType) }}
func main() { userService := &UserService{} normalUser, err := userService.CreateUser("张三", "zs@mail.com", UserTypeNormal) if err != nil { fmt.Println("创建普通用户失败,err: ", err) return } nUser := normalUser.(NormalUser) nUser.AddAddress(Address{ Province: "广东省", City: "深圳市", Street: "南山大道", Detail: "深圳南山大道100号", }) nUser.DisplayBasicInfo()
vipUser, err := userService.CreateUser("李四", "ls@mail.com", UserTypeVip) if err != nil { fmt.Println("创建VIP用户失败,err: ", err) return }
users := []interface{}{nUser, vipUser} for _, user := range users { switch u := user.(type) { case NormalUser: fmt.Println("普通用户ID:", u.ID) fmt.Println("普通用户创建时间:", u.GetCreateDate()) fmt.Println("普通用户地址:") for _, address := range u.Address { fmt.Println("-", address.GetFullAddress()) } case VipUser: fmt.Println("VIP用户ID:", u.ID) fmt.Println("VIP用户创建时间:", u.GetCreateDate()) fmt.Println("VIP用户等级:", u.VipLevel) fmt.Println("VIP用户折扣:", u.GetDiscount()) fmt.Println("VIP用户状态:", u.IsValid()) } }}package main
import "fmt"
/* 实现面向对象 1. 结构体代替类:使用结构体组织数据,方法通过接收者定义 2. 组合优于继承:通过结构体嵌入实现代码复用 3. 方法接收者:值接收者不修改原对象,指针接收者可以修改原对象 4. 接口实现多态:不同类型实现相同接口,提高代码灵活性 5. 方法提升:嵌入结构体的方法和字段会自动提升到外部结构体*/
type Notifier interface { Notify(message string) error}
type EmailNotify struct { SMTPHost string SMTPPort int}
func (e *EmailNotify) Notify(message string) error { fmt.Printf("发送邮件通知:%s\n", message) return nil}
type SMSNotify struct { Secret string TmplString string}
func (s *SMSNotify) Notify(message string) error { fmt.Printf("发送短信通知:%s\n", message) return nil}
type BroadCastNotify struct { notifiers []Notifier}
func (b *BroadCastNotify) Notify(message string) error { for _, n := range b.notifiers { err := n.Notify(message) if err != nil { return err } } return nil}
type OrderService struct { notifier Notifier}
func (o *OrderService) SetNotifier(n Notifier) { o.notifier = n}
func (o *OrderService) CreateOrder(product string, quantity int) { fmt.Printf("创建订单:%s, 数量:%d\n", product, quantity) err := o.notifier.Notify("订单创建成功") if err != nil { fmt.Println("通知失败,err: ", err) return }}
func main() { orderService := &OrderService{}
emailNotify := &EmailNotify{ SMTPHost: "smtp.qq.com", SMTPPort: 465, } smsNotify := &SMSNotify{ Secret: "ABCD1234", TmplString: "您的订单已创建成功", }
broadcastNotify := &BroadCastNotify{ notifiers: []Notifier{emailNotify, smsNotify}, }
orderService.SetNotifier(emailNotify) orderService.CreateOrder("商品1", 1)
orderService.SetNotifier(smsNotify) orderService.CreateOrder("商品2", 1)
orderService.SetNotifier(broadcastNotify) orderService.CreateOrder("商品3", 1)}