本篇概要:
1. interface、模拟用户服务;
- class 代表类、interface 代表接口。前者是对业务对象的封装或定义、后者是对业务对象的抽象
- 这些在 golang 里对应的是:struct 和 interface
抽象
-
抽象是具象的相对概念,是就多种事物抽出其共通之点,加以综合而成的一个新的概念,此概念叫抽象
-
程序层面
-
文件
/Users/go/go2/src/Object/Iservice.go
package Object
type IService interface {
Save()
}
- 文件
/Users/go/go2/src/Object/UserService.go
package Object
import "log"
type UserService struct {
}
func NewUserService() *UserService {
return &UserService{}
}
// 类方法
func(this *UserService) Save(){
log.Println("用户保存入库成功")
}
- 文件
/Users/go/go2/src/Object/ProductService.go
package Object
import "log"
type ProductService struct {
}
func NewProductService() *ProductService {
return &ProductService{}
}
// 类方法
func(this *ProductService) Save(){
log.Println("商品保存入库成功")
}
- 文件
/Users/go/go2/src/main.go
package main
import . "goplus/src/Object"
func main() {
var service IService = NewUserService()
service.Save()
}
2. 使用接口简化代码、链式调用;
- 文件
/Users/go/go2/src/Object/Iservice.go
package Object
type IService interface {
Save() IService // 保存一般不会返回值。这里只是演示
List() IService
}
- 文件
/Users/go/go2/src/Object/UserService.go
package Object
import "log"
type UserService struct {
}
func NewUserService() *UserService {
return &UserService{}
}
// 类方法,保存入库
func(this *UserService) Save() IService {
log.Println("用户保存入库成功")
return this
}
func(this *UserService) List() IService {
log.Println("用户列表获取")
return this
}
- 文件
/Users/go/go2/src/main.go
package main
import . "goplus/src/Object"
// 啰嗦的写法
//func SaveModel(service UserService) {
// service.Save()
//}
//func SaveModel2(service ProductService) {
// service.Save()
//}
// 把 save 过程封装和隐藏起来
//func SaveModel (service IService) {
// service.Save()
//}
func SaveModel (service IService) (IService) {
service.Save()
return service
}
func main() {
//s := NewUserService()
//s.Save()
//IService 可以代言 UserService 和 ProductService
// var service IService = NewUserService()
// service.Save()
// SaveModel(service)
// SaveModel(NewUserService())
// 链式调用
// SaveModel(NewUserService()).List()
// 演示
NewUserService().Save().List().Save().List()
}
3. 使用接口简化代码、传递接口参数和断言;
- 文件
/Users/go/go2/src/Object/User.go
package Object
type User struct {
Id int
Name string
Gender byte
}
// 有选择性的进行赋值(可变参数,参数类型是 function)
func NewUser(fs ...UserAttrFunc) (*User) {
u := new (User)
UserAttrFuncs(fs).apply(u)
return u
}
- 文件
/Users/go/go2/src/Object/UserAttrs.go
package Object
type UserAttrFunc func(*User) // 用来设置 User 属性的函数类型,参数可省略
type UserAttrFuncs []UserAttrFunc
func (this UserAttrFuncs) apply (u *User){
for _, f := range this {
f(u)
}
}
func WithUserId(id int) (UserAttrFunc) {
return func(u *User) {
u.Id = id
}
}
func WithUserName(name string) (UserAttrFunc) {
return func(u *User) {
u.Name = name
}
}
func WithUserGender(gender byte) (UserAttrFunc) {
return func(u *User) {
u.Gender = gender
}
}
- 文件
/Users/go/go2/src/Object/Iservice.go
package Object
type IService interface {
Save(data interface{}) IService // interface 通用类型
List() IService
}
- 文件
/Users/go/go2/src/Object/UserService.go
package Object
import "log"
type UserService struct {
}
func NewUserService() *UserService {
return &UserService{}
}
// 类方法,保存入库
// 断言:针对 interface 进行的 类型判断
func(this *UserService) Save(data interface{}) IService {
// 通过断言获取 user 真实的值
if user, ok := data.(*User); ok {
log.Printf("%v", user.Name) // 打印值
log.Println("用户保存入库成功")
} else {
log.Fatal("用户参数错误")
}
return this
}
func(this *UserService) List() IService {
log.Println("用户列表获取")
return this
}
- 文件
/Users/go/go2/src/main.go
package main
import . "goplus/src/Object"
func main() {
user := NewUser(
WithUserName("hua"),
WithUserId(202),
WithUserGender(1),
)
NewUserService().Save(user)
}
4. 反射入门、获取 Struct 所有属性、Elem 函数;
反射:
-
在运行时动态获取或设置变量的各种信息,比如变量的类型(type)、类别(kind)、值(value)
-
两个典型方法:
-
reflect.TypeOf(变量):专门用来处理类型
-
reflect.ValueOf(变量):专门用来处理值
-
另:Elem 函数:用来获取指针指向的变量,前提是传入的参数必须是指针才行
-
文件
/Users/go/go2/src/main.go
package main
import (
"fmt"
"reflect"
)
type User struct {
UserId int
UserName string
}
func main() {
// 获取对象
//u := User{}
//
//t := reflect.TypeOf(u)
//
//fmt.Println(t.Name()) // User
//fmt.Println(t.NumField()) // 多少属性:2
//
打印属性名
//for i :=0 ; i< t.NumField(); i++ {
// fmt.Println(t.Field(i).Name, t.Field(i).Type)
// //UserId int
// //Username string
//}
u := &User{}
t := reflect.TypeOf(u)
t = t.Elem() // 把 t 变成了指针指向的变量
for i :=0 ; i< t.NumField(); i++ {
fmt.Println(t.Field(i).Name, t.Field(i).Type)
}
}
5. Kind函数、获取struct属性值的两种方式;
- 文件
/Users/go/go2/src/main.go
package main
import (
"fmt"
"reflect"
)
type User struct {
UserId int
UserName string
}
func main() {
u := &User{101, "hua"}
// u := User{} // 下面的 if 判断很重要
t := reflect.ValueOf(u)
// 地址类型,写Ptr
if t.Kind() == reflect.Ptr {
t = t.Elem() // 把 t 变成了指针指向的变量
}
for i :=0 ; i< t.NumField(); i++ {
//if t.Field(i).Kind() == reflect.Int {
// fmt.Println(t.Field(i).Int())
//}
//if t.Field(i).Kind() == reflect.String {
// fmt.Println(t.Field(i).String())
//}
// interface 通用
// 101
// hua
fmt.Println(t.Field(i).Interface())
}
}
6. 利用反射设置 Struct 属性值、切片映射 Struct;
- 文件
/Users/go/go2/src/main.go
package main
import (
"fmt"
"reflect"
)
type User struct {
UserId int
UserName string
}
func main() {
u := &User{}
t := reflect.ValueOf(u)
// 地址类型,写Ptr
if t.Kind() == reflect.Ptr {
t = t.Elem() // 把 t 变成了指针指向的变量
}
for i :=0 ; i< t.NumField(); i++ {
// interface 通用
// fmt.Println(t.Field(i).Interface())
if t.Field(i).Kind() == reflect.Int {
t.Field(i).SetInt(12)
}
if t.Field(i).Kind() == reflect.String {
//t.Field(i).SetString("hua")
t.Field(i).Set(reflect.ValueOf("hua"))
}
}
fmt.Println(u)
// &{12 hua}
}
package main
import (
"fmt"
"reflect"
)
type User struct {
UserId int
UserName string
}
func main() {
u := &User{}
t := reflect.ValueOf(u)
// 地址类型,写Ptr
if t.Kind() == reflect.Ptr {
t = t.Elem() // 把 t 变成了指针指向的变量
}
values := []interface{}{202, "zhang"}
for i :=0 ; i< t.NumField(); i++ {
if t.Field(i).Kind() == reflect.ValueOf(values[i]).Kind() {
t.Field(i).Set(reflect.ValueOf(values[i]))
}
}
fmt.Println(u)
}
7. 把 map 映射成 struct;
package main
import (
"fmt"
"reflect"
)
type User struct {
UserId int
UserName string
}
func Map2Struct(m map[string]interface{}, u interface{}) {
v := reflect.ValueOf(u)
if v.Kind() == reflect.Ptr {
v = v.Elem()
if v.Kind() != reflect.Struct {
panic("must struct")
}
findFromMap := func(key string) interface{} {
for k, v := range m {
if k == key {
return v
}
}
return nil
}
for i :=0; i<v.NumField(); i++ {
get_value := findFromMap(v.Type().Field(i).Name)
if get_value != nil && reflect.ValueOf(get_value).Kind() == v.Field(i).Kind() {
v.Field(i).Set(reflect.ValueOf(get_value))
}
}
} else {
panic("must ptr")
}
}
func main() {
u := &User{}
m := map[string]interface{}{
"id" : 123,
"UserId": 101,
"UserName": "hua",
"age": 19,
}
Map2Struct(m,u)
fmt.Println(u)
}