Golang 的结构体没有构造函数,通常可以使用工厂模式来解决这个问题。
一个结构体的声明:
package model
type Student struct{
Name string ...
}
因为这里的Student 的首字母S是大写的,如果我们想在其它包括创建Student 的实例(比如main包),引入model 包后,就可以直接创建Student 结构体的变量(实例)。但是问题来了,如果首字母是小写的,比如是:
type student struct{
...
}
那么直接使用就不行了,这时候该怎么办呢? 使用工厂模式来解决!
package model
// 定义一个结构体
type Student struct{
Name string
Score float64
}
main包代码:
package main
import (
"fmt"
"xxx/xx..xx/xxx/model" // src 下目录名称
)
func main(){
var str = model.Student{
Name : "tom",
Score: "66.6",
}
fmt.Println(stu)
}
model包代码:
package model
// 定义一个结构体
type Student struct{
Name string
Score float64
}
// 因为student 结构体首字母是小写,因此是只能在model 使用
// 我们通过工厂模式来解决
func NewStudent(n string, s float64) *student{
return &student{
Name : n,
Score : s,
}
}
main包代码:
package main
import (
"fmt"
"xxx/xx..xx/xxx/model" // src 下目录名称
)
func main(){
var stu = model.NewStudent("tom~", 88.8) // 返回的也是指针
fmt.Println(stu)// &(.......)
fmt.Println(*stu)// 返回值
fmt.Println(stu.Score)// 这个编译器可以做(*stu) 默认处理。
}
model包代码:
package model
// 定义一个结构体
type Student struct{
Name string
score float64
}
// 因为student 结构体首字母是小写,因此是只能在model 使用
// 我们通过工厂模式来解决
func NewStudent(n string, s float64) *student{
return &student{
Name : n,
score : s,
}
}
//获取score 方法
func (s *student) GetScore() float64{
// return (*s).score
return s.score
}
main包代码:
package main
import (
"fmt"
"xxx/xx..xx/xxx/model" // src 下目录名称
)
func main(){
var stu = model.NewStudent("tom~", 88.8) // 返回的也是指针
fmt.Println(stu)// &(.......)
fmt.Println(*stu)// 返回值
fmt.Println(stu.GetScore())// 这个编译器可以做(*stu) 默认处理。
}
以上讲解了工厂模式的小例子,实际在我们实际开发过程中结构要复杂一些,接下来我们就讨论下抽象工厂模式,如下:
抽象工厂模式常用于程序适配多种数据库,以达到开放扩展关闭修改的原则。
首先需要有一个思想就是数据库表结构都是固定,但是每种数据库语言存在差异性,因此使用接口规范功能,各种数据库有自己不同的语言实现,业务中也是使用接口操作,运行时根据配置实例化各种数据库实现。好处是增加新的数据库时,只需要用新的数据库语言实现即可,不用修改原来的代码。部署程序时,只需要修改配置即可适配不同的数据库。
myProject/MyORM/Model/User.go
package Model
type User struct {
Id int
UID string
LoginName string
PassWord string
}
func (t *User) TableName() string {
return "User"
}
myProject/MyORM/Model/Product.go
package Model
type Product struct {
Id int
UID string
Name string
Price float64
}
func (t *Product) TableName() string {
return "Product"
}
myProject/MyORM/Data/IUser.go
package Data
import (
"myProject/MyORM/Model"
)
type IUser interface {
Add(entity *Model.User) bool
Edit(entity *Model.User) Model.User
}
myProject/MyORM/Data/IProduct.go
package Data
import (
"myProject/MyORM/Model"
)
type IProduct interface {
Add(entity *Model.Product) bool
Edit(entity *Model.Product) Model.Product
}
myProject/MyORM/Data/IProvider.go
♥ 抽象工厂接口
package Data
type IProvider interface {
GetUser() IUser
GetProduct() IProduct
}
♣ 注意:Go语言的接口实现是隐式的,无须让实现接口的类型写出实现了哪些接口。这个设计被称为非侵入式设计。在类型中添加与接口签名一致的方法就可以实现该方法。
myProject/MyORM/SqlData/SqlUser.go
package SqlData
import (
"fmt"
"myProject/MyORM/Model"
)
type SqlUser struct {
}
func (p *SqlUser) Add(entity *Model.User) bool {
fmt.Println("sql执行UserAdd")
return true
}
func (p *SqlUser) Edit(entity *Model.User) Model.User {
fmt.Println("sql执行UserEdit")
return *entity
}
myProject/MyORM/SqlData/SqlProduct.go
package SqlData
import (
"fmt"
"myProject/MyORM/Model"
)
type SqlProduct struct {
}
func (p *SqlProduct) Add(entity *Model.Product) bool {
fmt.Println("sql执行ProductAdd")
return true
}
func (p *SqlProduct) Edit(entity *Model.Product) Model.Product {
fmt.Println("sql执行ProductEdit")
return *entity
}
myProject/MyORM/SqlData/SqlProvider.go
♥ SQL工厂实现
package SqlData
import (
"myProject/MyORM/Data"
)
type SqlProvider struct {
}
func (p *SqlProvider) GetUser() Data.IUser {
return new(SqlUser)
}
func (p *SqlProvider) GetProduct() Data.IProduct {
return new(SqlProduct)
}
myProject/MyORM/MysqlData/MysqlUser.go
package MysqlData
import (
"fmt"
"myProject/MyORM/Model"
)
type MysqlUser struct {
}
func (p *MysqlUser) Add(entity *Model.User) bool {
fmt.Println("mysql执行UserAdd")
return true
}
func (p *MysqlUser) Edit(entity *Model.User) Model.User {
fmt.Println("mysql执行UserEdit")
return *entity
}
myProject/MyORM/MysqlData/MysqlProduct.go
package MysqlData
import (
"fmt"
"myProject/MyORM/Model"
)
type MysqlProduct struct {
}
func (p *MysqlProduct) Add(entity *Model.Product) bool {
fmt.Println("mysql执行ProductAdd")
return true
}
func (p *MysqlProduct) Edit(entity *Model.Product) Model.Product {
fmt.Println("mysql执行ProductEdit")
return *entity
}
myProject/MyORM/MysqlData/MysqlProvider.go
♥ MYSQL工厂实现
package MysqlData
import (
"myProject/MyORM/Data"
)
type MysqlProvider struct {
}
func (p *MysqlProvider) GetUser() Data.IUser {
return new(MysqlUser)
}
func (p *MysqlProvider) GetProduct() Data.IProduct {
return new(MysqlProduct)
}
myProject/MyORM/Service/Factory.go
package Service
import (
"myProject/MyORM/Data"
"myProject/MyORM/MysqlData"
"myProject/MyORM/SqlData"
)
// 设置配置
const db = "sql"
// 简单工厂方法,根据配置加载不同的实现库
func Provider() Data.IProvider {
switch db {
case "sql":
return new(SqlData.SqlProvider)
case "mysql":
return new(MysqlData.MysqlProvider)
default:
panic("无法映射配置的数据库")
}
}
myProject/MyORM/Service/UserService.go
package Service
import (
"myProject/MyORM/Data"
"myProject/MyORM/Model"
)
type UserService struct {
}
var user Data.IUser
func init() {
user = Provider().GetUser()
}
func (u *UserService) Add(entity *Model.User) bool {
return user.Add(entity)
}
func (u *UserService) Update(entity *Model.User) Model.User {
return user.Edit(entity)
}
myProject/MyORM/Service/ProductService.go
package Service
import (
"myProject/MyORM/Data"
"myProject/MyORM/Model"
)
type ProductService struct {
}
var product Data.IProduct
func init() {
product = Provider().GetProduct()
}
func (p *ProductService) Add(entity *Model.Product) bool {
return product.Add(entity)
}
func (p *ProductService) Update(entity *Model.Product) Model.Product {
return product.Edit(entity)
}
myProject/MyORM/main.go
package main
import (
"myProject/MyORM/Model"
"myProject/MyORM/Service"
)
func main() {
user := &Model.User{
Id: 1,
UID: "12124545",
LoginName: "admin",
PassWord: "123454",
}
userService := new(Service.UserService)
userService.Add(user)
product := &Model.Product{
Id: 1,
UID: "12124545",
Name: "苹果",
Price: 12.5,
}
productService := new(Service.ProductService)
productService.Update(product)
}
参考资料:
Go语言工厂模式
https://studygolang.com/articles/25696?fr=sidebar
Go语言抽象工厂模式
https://www.cnblogs.com/shi2310/p/10899458.html