作者:kaysun,腾讯 PCG 后台开发工程师
1. 抽象工厂模式
abstract_factory.go
// package abstract_factory 抽象工厂模式
package abstract_factory
import "fmt"
// FruitFactory 水果工厂接口
type FruitFactory interface {
// CreateFruit 生产水果
CreateFruit() Fruit
}
//AppleFactory 苹果工厂,实现FruitFactory接口
type AppleFactory struct{}
//BananaFactory 香蕉工厂,实现FruitFactory接口
type BananaFactory struct{}
//OrangeFactory 橘子工厂,实现FruitFactory接口
type OrangeFactory struct{}
// CreateFruit 苹果工厂生产苹果
func (appleFactory AppleFactory) CreateFruit() Fruit {
return &Apple{}
}
// CreateFruit 香蕉工厂生产香蕉
func (bananaFactory BananaFactory) CreateFruit() Fruit {
return &Banana{}
}
// CreateFruit 橘子工厂生产橘子
func (orangeFactory OrangeFactory) CreateFruit() Fruit {
return &Orange{}
}
// Fruit 水果接口
type Fruit interface {
// Eat 吃水果
Eat()
}
// Apple 苹果,实现Fruit接口
type Apple struct{}
// Banana 香蕉,实现Fruit接口
type Banana struct{}
// Orange 橘子,实现Fruit接口
type Orange struct{}
// Eat 吃苹果
func (apple Apple) Eat() {
fmt.Println("吃苹果")
}
// Eat 吃香蕉
func (banana Banana) Eat() {
fmt.Println("吃香蕉")
}
// Eat 吃橘子
func (orange Orange) Eat() {
fmt.Println("吃橘子")
}
abstract_factory_test.go
package abstract_factory
import "testing"
func Test(t *testing.T) {
t.Run("abstract_factory: ", ProduceFruitAndEat)
}
func ProduceFruitAndEat(t *testing.T) {
var factory FruitFactory
var apple, banana, orange Fruit
//创建苹果工厂,生产苹果,吃苹果
factory = &AppleFactory{}
apple = factory.CreateFruit()
apple.Eat()
//创建香蕉工厂,生产香蕉,吃香蕉
factory = &BananaFactory{}
banana = factory.CreateFruit()
banana.Eat()
//创建橘子工厂,生产橘子,吃橘子
factory = &OrangeFactory{}
orange = factory.CreateFruit()
orange.Eat()
}
2. 适配器模式
adapter.go
// package adapter 适配器,以手机充电为例,适配器将220v电压转为5v电压
package adapter
import "fmt"
// Volts220 源结构体,电压220v
type Volts220 struct{}
// OutputPower 输出电压,实现了Adaptee接口
func (v Volts220) OutputPower() {
fmt.Println("电源输出了220V电压")
}
// Adaptee 源接口
type Adaptee interface {
// OutputPower 输出电压
OutputPower()
}
// Target 目的接口
type Target interface {
// CovertTo5V 转换到5V电压
CovertTo5V()
}
// Adapter 适配器结构体,嵌套Adaptee接口,实现Target接口
type Adapter struct {
Adaptee
}
// CovertTo5V 转换到5V电压
func (a Adapter) CovertTo5V() {
//这里实现自己的转换逻辑,会调用源结构体的方法
a.OutputPower()
fmt.Println("通过手机电源适配器,转成了5V电压,可供手机充电")
}
adapter_test.go
// package adapter 适配器,以手机充电为例,适配器将220v电压转为5v电压
package adapter
import "fmt"
// Volts220 源结构体,电压220v
type Volts220 struct{}
// OutputPower 输出电压,实现了Adaptee接口
func (v Volts220) OutputPower() {
fmt.Println("电源输出了220V电压")
}
// Adaptee 源接口
type Adaptee interface {
// OutputPower 输出电压
OutputPower()
}
// Target 目的接口
type Target interface {
// CovertTo5V 转换到5V电压
CovertTo5V()
}
// Adapter 适配器结构体,嵌套Adaptee接口,实现Target接口
type Adapter struct {
Adaptee
}
// CovertTo5V 转换到5V电压
func (a Adapter) CovertTo5V() {
//这里实现自己的转换逻辑,会调用源结构体的方法
a.OutputPower()
fmt.Println("通过手机电源适配器,转成了5V电压,可供手机充电")
}
3. 桥接模式
bridge.go
// package bridge 桥接模式,以订购咖啡为例,两个纬度,分别为大中小杯,加糖加奶
package bridge
import "fmt"
// ICoffee 咖啡接口
type ICoffee interface {
// OrderCoffee 订购咖啡
OrderCoffee()
}
// LargeCoffee 大杯咖啡,实现ICoffee接口
type LargeCoffee struct {
ICoffeeAddtion
}
// MediumCoffee 中杯咖啡,实现ICoffee接口
type MediumCoffee struct {
ICoffeeAddtion
}
// SmallCoffee 小杯咖啡,实现ICoffee接口
type SmallCoffee struct {
ICoffeeAddtion
}
// OrderCoffee 订购大杯咖啡
func (lc LargeCoffee) OrderCoffee() {
fmt.Println("订购了大杯咖啡")
lc.AddSomething()
}
// OrderCoffee 订购中杯咖啡
func (mc MediumCoffee) OrderCoffee() {
fmt.Println("订购了中杯咖啡")
mc.AddSomething()
}
// OrderCoffee 订购小杯咖啡
func (sc SmallCoffee) OrderCoffee() {
fmt.Println("订购了小杯咖啡")
sc.AddSomething()
}
// CoffeeCupType 咖啡容量类型
type CoffeeCupType uint8
const (
// CoffeeCupTypeLarge 大杯咖啡
CoffeeCupTypeLarge = iota
// CoffeeCupTypeMedium 中杯咖啡
CoffeeCupTypeMedium = iota
// CoffeeCupTypeSmall 小杯咖啡
CoffeeCupTypeSmall = iota
)
// CoffeeFuncMap 全局可导出变量,咖啡类型与创建咖啡对象的map,用于减小圈复杂度
var CoffeeFuncMap = map[CoffeeCupType]func(coffeeAddtion ICoffeeAddtion) ICoffee{
CoffeeCupTypeLarge: NewLargeCoffee,
CoffeeCupTypeMedium: NewMediumCoffee,
CoffeeCupTypeSmall: NewSmallCoffee,
}
// NewCoffee 创建咖啡接口对象的简单工厂,根据咖啡容量类型,获取创建接口对象的func
func NewCoffee(cupType CoffeeCupType, coffeeAddtion ICoffeeAddtion) ICoffee {
if handler, ok := CoffeeFuncMap[cupType]; ok {
return handler(coffeeAddtion)
}
return nil
}
// NewLargeCoffee 创建大杯咖啡对象
func NewLargeCoffee(coffeeAddtion ICoffeeAddtion) ICoffee {
return &LargeCoffee{coffeeAddtion}
}
// NewMediumCoffee 创建中杯咖啡对象
func NewMediumCoffee(coffeeAddtion ICoffeeAddtion) ICoffee {
return &MediumCoffee{coffeeAddtion}
}
// NewSmallCoffee 创建小杯咖啡对象
func NewSmallCoffee(coffeeAddtion ICoffeeAddtion) ICoffee {
return &SmallCoffee{coffeeAddtion}
}
// ICoffeeAddtion 咖啡额外添加接口
type ICoffeeAddtion interface {
//AddSomething 添加某种食物
AddSomething()
}
// Milk 加奶,实现ICoffeeAddtion接口
type Milk struct{}
// Sugar 加糖,实现ICoffeeAddtion接口
type Sugar struct{}
// AddSomething Milk实现加奶
func (milk Milk) AddSomething() {
fmt.Println("加奶")
}
//AddSomething Sugar实现加糖
func (sugar Sugar) AddSomething() {
fmt.Println("加糖")
}
// CoffeeAddtionType 咖啡额外添加类型
type CoffeeAddtionType uint8
const (
// CoffeeAddtionTypeMilk 咖啡额外添加牛奶
CoffeeAddtionTypeMilk = iota
// CoffeeAddtionTypeSugar 咖啡额外添加糖
CoffeeAddtionTypeSugar = iota
)
// CoffeeAddtionFuncMap 全局可导出变量,咖啡额外添加类型与创建咖啡额外添加对象的map,用于减小圈复杂度
var CoffeeAddtionFuncMap = map[CoffeeAddtionType]func() ICoffeeAddtion{
CoffeeAddtionTypeMilk: NewCoffeeAddtionMilk,
CoffeeAddtionTypeSugar: NewCoffeeAddtionSugar,
}
// NewCoffeeAddtion 创建咖啡额外添加接口对象的简单工厂,根据咖啡额外添加类型,获取创建接口对象的func
func NewCoffeeAddtion(addtionType CoffeeAddtionType) ICoffeeAddtion {
if handler, ok := CoffeeAddtionFuncMap[addtionType]; ok {
return handler()
}
return nil
}
// NewCoffeeAddtionMilk 创建咖啡额外加奶
func NewCoffeeAddtionMilk() ICoffeeAddtion {
return &Milk{}
}
// NewCoffeeAddtionMilk 创建咖啡额外加糖
func NewCoffeeAddtionSugar() ICoffeeAddtion {
return &Sugar{}
}
bridge_test.go
package bridge
import "testing"
func Test(t *testing.T) {
t.Run("large-milk: ", OrderLargeMilkCoffee)
t.Run("large-sugar: ", OrderLargeSugarCoffee)
t.Run("medium-milk: ", OrderMediumMilkCoffee)
t.Run("smarll-sugar: ", OrderSmallSugarCoffee)
}
func OrderLargeMilkCoffee(t *testing.T) {
var coffeeAddtion ICoffeeAddtion
coffeeAddtion = NewCoffeeAddtion(CoffeeAddtionTypeMilk)
var coffee ICoffee
coffee = NewCoffee(CoffeeCupTypeLarge, coffeeAddtion)
coffee.OrderCoffee()
}
func OrderLargeSugarCoffee(t *testing.T) {
var coffeeAddtion ICoffeeAddtion
coffeeAddtion = NewCoffeeAddtion(CoffeeAddtionTypeSugar)
var coffee ICoffee
coffee = NewCoffee(CoffeeCupTypeLarge, coffeeAddtion)
coffee.OrderCoffee()
}
func OrderMediumMilkCoffee(t *testing.T) {
var coffeeAddtion ICoffeeAddtion
coffeeAddtion = NewCoffeeAddtion(CoffeeAddtionTypeMilk)
var coffee ICoffee
coffee = NewCoffee(CoffeeCupTypeMedium, coffeeAddtion)
coffee.OrderCoffee()
}
func OrderSmallSugarCoffee(t *testing.T) {
var coffeeAddtion ICoffeeAddtion
coffeeAddtion = NewCoffeeAddtion(CoffeeAddtionTypeSugar)
var coffee ICoffee
coffee = NewCoffee(CoffeeCupTypeSmall, coffeeAddtion)
coffee.OrderCoffee()
}
4. 建造者模式
builder.go
//package builder 建造者模式
package builder
const (
// Success 成功
Success = 0
// ErrCodeNameRequired 名字必填
ErrCodeNameRequired = -10001
// ErrCodeMinIdleMoreThanMaxIdle 最小空闲数超过了最大空闲数
ErrCodeMinIdleMoreThanMaxIdle = -10002
// ErrCodeMaxTotalLessThanOrEqualToZero 最大连接数必须大于0
ErrCodeMaxTotalMustMoreThanZero = -10003
// ErrCodeMaxIdleMustMoreThanZero 最大空闲数必须大于0
ErrCodeMaxIdleMustMoreThanZero = -10004
// ErrCodeMinIdleMustMoreThanZero 最小空闲数必须大于0
ErrCodeMinIdleMustMoreThanZero = -10005
// ErrCodeMaxTotalNotSet 最大连接数未设置
ErrCodeMaxTotalNotSet = -10006
// ErrCodeMaxIdleNotSet 最大空闲连接数未设置
ErrCodeMaxIdleNotSet = -10007
// ErrCodeMinIdleNotSet 最小空闲连接数未设置
ErrCodeMinIdleNotSet = -10008
)
// errMap 错误信息与错误码的配置
var errMap = map[int16]string{
Success: "ok",
ErrCodeNameRequired: "名字必填",
ErrCodeMinIdleMoreThanMaxIdle: "最小空闲数超过了最大空闲数",
ErrCodeMaxTotalMustMoreThanZero: "最大连接数必须大于0",
ErrCodeMaxIdleMustMoreThanZero: "最大空闲连接数必须大于0",
ErrCodeMinIdleMustMoreThanZero: "最小空闲连接数必须大于0",
ErrCodeMaxTotalNotSet: "最大连接数未设置",
ErrCodeMaxIdleNotSet: "最大空闲连接数未设置",
ErrCodeMinIdleNotSet: "最小空闲连接数未设置",
}
// resourcePoolConfig 资源池配置,不可导出
type resourcePoolConfig struct {
// name 名字,不可导出,必填
name string
// maxTotal 最大连接数,不可导出,必填
maxTotal uint16
// maxIdle 最大空闲连接数,不可导出,必填
maxIdle uint16
// minIdle 最小空闲连接数,不可导出,不必填,但填写必须大于0
minIdle uint16
}
// Builder 建造者接口
type Builder interface {
// Build 创建对象
Build() int16
}
// ResourcePoolBuild 资源池建造者,实现Builder接口
type ResourcePoolBuild struct {
// resourcePoolConfig 嵌套资源池配置
resourcePoolConfig
}
// Build 创建对象
func (build *ResourcePoolBuild) Build() int16 {
// 这一串的判断可以保证builder里要求必须设置的属性,都能够设置
if len(build.name) == 0 {
return ErrCodeNameRequired
}
if build.maxTotal == 0 {
return ErrCodeMaxTotalNotSet
}
if build.maxIdle == 0 {
return ErrCodeMaxIdleNotSet
}
// 对设置后的对象,做整体的逻辑性验证
if build.minIdle > build.maxIdle {
return ErrCodeMinIdleMoreThanMaxIdle
}
return Success
}
// SetName 设置名字,并进行校验
func (build *ResourcePoolBuild) SetName(name string) int16 {
if len(name) == 0 {
return ErrCodeNameRequired
}
build.name = name
return Success
}
// SetMaxTotal 设置最大连接数,并进行校验
func (build *ResourcePoolBuild) SetMaxTotal(maxTotal uint16) int16 {
if maxTotal <= 0 {
return ErrCodeMaxTotalMustMoreThanZero
}
build.maxTotal = maxTotal
return Success
}
// SetMaxIdle 设置最大空闲连接数,并信息校验
func (build *ResourcePoolBuild) SetMaxIdle(maxIdle uint16) int16 {
if maxIdle <= 0 {
return ErrCodeMaxIdleMustMoreThanZero
}
build.maxIdle = maxIdle
return Success
}
// SetMinIdle 设置最小空闲连接数,并进行校验
func (build *ResourcePoolBuild) SetMinIdle(minIdle uint16) int16 {
if minIdle <= 0 {
return ErrCodeMinIdleMustMoreThanZero
}
build.minIdle = minIdle
return Success
}
builder_test.go
package builder
import (
"fmt"
"testing"
)
func Test(t *testing.T) {
t.Run("builder-maxTotalNotSet: ", maxTotalNotSet)
t.Run("builder-minIdleMoreThanMaxIdle: ", minIdleMoreThanMaxIdle)
t.Run("builder-buildSuccess: ", buildSuccess)
}
func maxTotalNotSet(t *testing.T) {
// 此为示例代码,在实践中,不应将建造者与使用者放在一个包内,所以这里假设不能直接访问resourcePoolConfig
build := &ResourcePoolBuild{}
build.SetName("mysql连接池")
build.SetMaxIdle(10)
errCode := build.Build()
fmt.Println(fmt.Sprintf("建造资源池配置:%s", errMap[errCode]))
}
func minIdleMoreThanMaxIdle(t *testing.T) {
// 此为示例代码,在实践中,不应将建造者与使用者放在一个包内,所以这里假设不能直接访问resourcePoolConfig
build := &ResourcePoolBuild{}
build.SetName("mysql连接池")
build.SetMaxIdle(10)
build.SetMinIdle(20)
build.SetMaxTotal(50)
errCode := build.Build()
fmt.Println(fmt.Sprintf("建造资源池配置:%s", errMap[errCode]))
}
func buildSuccess(t *testing.T) {
// 此为示例代码,在实践中,不应将建造者与使用者放在一个包内,所以这里假设不能直接访问resourcePoolConfig
build := &ResourcePoolBuild{}
build.SetName("mysql连接池")
build.SetMaxIdle(10)
build.SetMinIdle(5)
build.SetMaxTotal(50)
errCode := build.Build()
fmt.Println(fmt.Sprintf("建造资源池配置:%s", errMap[errCode]))
}
5. 组合模式
component.go
//package combination 组合模式
package combination
// UIComponent UI组件接口,对于任何UI控件都适用。
type UIComponent interface {
// PrintUIComponent 打印UI组件
PrintUIComponent()
// GetUIControlName 获取控件名字
GetUIControlName() string
// GetConcreteUIControlName 获取控件具体名字
GetConcreteUIControlName() string
}
// UIComponentAddtion UI组件附加接口,使用接口隔离原则,保证不需要实现接口声明方法的结构体,没有额外负担。仅对容器类型对UI控件适用。
type UIComponentAddtion interface {
// AddUIComponent 添加UI组件
AddUIComponent(component UIComponent)
// AddUIComponents 添加UI组件列表
AddUIComponents(components []UIComponent)
// GetUIComponentList 获取UI组件列表
GetUIComponentList() []UIComponent
}
// UIAttr UI属性
type UIAttr struct {
// UI 名字
Name string
}
//client 打印client
var client = &PrintClient{}
container.go
package combination
// WinForm 窗口,实现UIComponent、UIComponentAddtion接口
type WinForm struct {
// UIAttr 嵌套UI属性
UIAttr
// Components 容器的组件列表
Components []UIComponent
}
// GetUIControlName 获取控件名字
func (window *WinForm) GetUIControlName() string {
return "WinForm"
}
// GetConcreteUIControlName 获取控件具体名字
func (window *WinForm) GetConcreteUIControlName() string {
return window.Name
}
// PrintUIComponent 打印UI组件
func (window *WinForm) PrintUIComponent() {
client.printContainer(window, window)
}
// AddUIComponent 添加UI组件
func (window *WinForm) AddUIComponent(component UIComponent) {
window.Components = append(window.Components, component)
}
// AddUIComponents 添加UI组件列表
func (window *WinForm) AddUIComponents(components []UIComponent) {
window.Components = append(window.Components, components...)
}
// GetUIComponentList 获取UI组件列表
func (window *WinForm) GetUIComponentList() []UIComponent {
return window.Components
}
// Frame 框架,实现UIComponent、接口
type Frame struct {
// UIAttr 嵌套UI属性
UIAttr
// Components 容器的组件列表
Components []UIComponent
}
// GetUIControlName 获取控件名字
func (frame *Frame) GetUIControlName() string {
return "Frame"
}
// GetConcreteUIControlName 获取控件具体名字
func (frame *Frame) GetConcreteUIControlName() string {
return frame.Name
}
// PrintUIComponent 打印UI组件
func (frame *Frame) PrintUIComponent() {
client.printContainer(frame, frame)
}
// AddUIComponent 添加UI组件
func (frame *Frame) AddUIComponent(component UIComponent) {
frame.Components = append(frame.Components, component)
}
// AddUIComponents 添加UI组件列表
func (frame *Frame) AddUIComponents(components []UIComponent) {
frame.Components = append(frame.Components, components...)
}
// GetUIComponentList 获取UI组件列表
func (frame *Frame) GetUIComponentList() []UIComponent {
return frame.Components
}
leaf.go
package combination
// Picture 图片,实现UIComponent接口
type Picture struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (picture Picture) GetUIControlName() string {
return "Picture"
}
// GetConcreteUIControlName 获取控件具体名字
func (picture Picture) GetConcreteUIControlName() string {
return picture.Name
}
// PrintUIComponent 打印UI组件
func (picture Picture) PrintUIComponent() {
client.printCurrentControl(picture)
}
// Button 按钮,实现UIComponent接口
type Button struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (button Button) GetUIControlName() string {
return "Button"
}
// GetConcreteUIControlName 获取控件具体名字
func (button Button) GetConcreteUIControlName() string {
return button.Name
}
// PrintUIComponent 打印UI组件
func (button Button) PrintUIComponent() {
client.printCurrentControl(button)
}
// Label 标签,实现UIComponent接口
type Label struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (label Label) GetUIControlName() string {
return "Label"
}
// GetConcreteUIControlName 获取控件具体名字
func (label Label) GetConcreteUIControlName() string {
return label.Name
}
// PrintUIComponent 打印UI组件
func (label Label) PrintUIComponent() {
client.printCurrentControl(label)
}
// TextBox 文本框,实现UIComponent接口
type TextBox struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (textBox TextBox) GetUIControlName() string {
return "TextBox"
}
// GetConcreteUIControlName 获取控件具体名字
func (textBox TextBox) GetConcreteUIControlName() string {
return textBox.Name
}
// PrintUIComponent 打印UI组件
func (textBox TextBox) PrintUIComponent() {
client.printCurrentControl(textBox)
}
// PassWordBox 密码框,实现UIComponent接口
type PassWordBox struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (passWordBox PassWordBox) GetUIControlName() string {
return "PassWordBox"
}
// GetConcreteUIControlName 获取控件具体名字
func (passWordBox PassWordBox) GetConcreteUIControlName() string {
return passWordBox.Name
}
// PrintUIComponent 打印UI组件
func (passWordBox PassWordBox) PrintUIComponent() {
client.printCurrentControl(passWordBox)
}
// CheckBox 复选框,实现UIComponent接口
type CheckBox struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (checkBox CheckBox) GetUIControlName() string {
return "CheckBox"
}
// GetConcreteUIControlName 获取控件具体名字
func (checkBox CheckBox) GetConcreteUIControlName() string {
return checkBox.Name
}
// PrintUIComponent 打印UI组件
func (checkBox CheckBox) PrintUIComponent() {
client.printCurrentControl(checkBox)
}
// LinkLabel 关联的标签,实现UIComponent接口
type LinkLabel struct {
// UIAttr 嵌套UI属性
UIAttr
}
// GetUIControlName 获取控件名字
func (linkLabel LinkLabel) GetUIControlName() string {
return "LinkLabel"
}
// GetConcreteUIControlName 获取控件具体名字
func (linkLabel LinkLabel) GetConcreteUIControlName() string {
return linkLabel.Name
}
// PrintUIComponent 打印UI组件
func (linkLabel LinkLabel) PrintUIComponent() {
client.printCurrentControl(linkLabel)
}
client.go
package combination
import "fmt"
// PrintClient 打印客户端
type PrintClient struct{}
// printContainer 打印容器控件
func (client PrintClient) printContainer(component UIComponent, componentAddtion UIComponentAddtion) {
client.printCurrentControl(component)
for _, v := range componentAddtion.GetUIComponentList() {
v.PrintUIComponent()
}
}
// printCurrentControl 打印当前控件
func (client PrintClient) printCurrentControl(component UIComponent) {
fmt.Println(fmt.Sprintf("print %s(%s)", component.GetUIControlName(), component.GetConcreteUIControlName()))
}
combination_test.go
package combination
import (
"testing"
)
func Test(t *testing.T) {
t.Run("combination: ", Combination)
}
// Combination 单元测试
//print WinForm(WINDOW窗口)
//print Picture(LOGO图片)
//print Button(登录)
//print Button(注册)
//print Frame(FRAME1)
//print Label(用户名)
//print TextBox(文本框)
//print Label(密码)
//print PassWordBox(密码框)
//print CheckBox(复选框)
//print TextBox(记住用户名)
//print LinkLabel(忘记密码)
func Combination(t *testing.T) {
window := &WinForm{UIAttr: UIAttr{Name: "WINDOW窗口"}}
picture := &Picture{UIAttr{Name: "LOGO图片"}}
loginButton := &Button{UIAttr{Name: "登录"}}
registerButton := &Button{UIAttr{Name: "注册"}}
frame := &Frame{UIAttr: UIAttr{Name: "FRAME1"}}
userLable := &Label{UIAttr{Name: "用户名"}}
textBox := &TextBox{UIAttr{Name: "文本框"}}
passwordLable := &Label{UIAttr{Name: "密码"}}
passwordBox := &PassWordBox{UIAttr{Name: "密码框"}}
checkBox := &CheckBox{UIAttr{Name: "复选框"}}
rememberUserTextBox := &TextBox{UIAttr{Name: "记住用户名"}}
linkLable := &LinkLabel{UIAttr{Name: "忘记密码"}}
window.AddUIComponents([]UIComponent{picture, loginButton, registerButton, frame})
frame.AddUIComponents([]UIComponent{userLable, textBox, passwordLable, passwordBox, checkBox, rememberUserTextBox, linkLable})
window.PrintUIComponent()
}
6. 命令模式
command.go
// package command 命令模式,引入调用者和接收者实现解耦
package command
import "fmt"
// Command 命令接口
type Command interface {
// Execute 执行命令
Execute()
}
// CreateCommand 创建命令,实现Command接口
type CreateCommand struct {
// receiver 接收者接口对象
receiver Receiver
}
// UpdateCommand 更新命令,实现Command接口
type UpdateCommand struct {
// receiver 接收者接口对象
receiver Receiver
}
// Execute 创建命令实现执行命令方法
func (command CreateCommand) Execute() {
command.receiver.Action()
}
// Execute 修改命令实现执行命令方法
func (command UpdateCommand) Execute() {
command.receiver.Action()
}
// Receiver 接收者接口
type Receiver interface {
// Action 动作
Action()
}
// CreateReceiver 创建接收者,实现Receiver接口
type CreateReceiver struct{}
// UpdateReceiver 更新接收者,实现Receiver接口
type UpdateReceiver struct{}
func (receiver CreateReceiver) Action() {
fmt.Println("执行了创建")
}
func (receiver UpdateReceiver) Action() {
fmt.Println("执行了修改")
}
// Invoker 调用者
type Invoker struct {
// command 命令接口对象
command Command
}
// Call 调用者调用执行命令方法
func (invoker Invoker) Call() {
invoker.command.Execute()
}
command_test.go
package command
import "testing"
func Test(t *testing.T) {
t.Run("create_command: ", CreateCommandExecute)
t.Run("update_command: ", UpdateCommandExecute)
}
func CreateCommandExecute(t *testing.T) {
var receiver Receiver
receiver = &CreateReceiver{}
var command Command
command = &CreateCommand{receiver: receiver}
invoker := Invoker{command: command}
invoker.Call()
}
func UpdateCommandExecute(t *testing.T) {
var receiver Receiver
receiver = &UpdateReceiver{}
var command Command
command = &UpdateCommand{receiver: receiver}
invoker := Invoker{command: command}
invoker.Call()
}
7. 装饰者模式
decorator_add.go
// package decorator 装饰者模式,在运行期动态地给对象添加额外的指责,比子类更灵活。第二个功能:用于添加功能的装饰模式。
// 若不想修改原来的接口,则可以使用装饰者。go这种语言,若增加接口的方法,则原来实现接口的结构体都需要增加一个新方法,这样就不符合开闭原则了。
package decorator
import "fmt"
// Booker 书的接口
type Booker interface {
// Reading 读书
Reading()
}
// Book 书,实现Booker接口
type Book struct {
}
// Reading 读书,实现Booker接口
func (book Book) Reading() {
fmt.Println("我正在读书")
}
// Underliner 划线接口,装饰者接口
type Underliner interface {
// Booker 继承Booker接口
Booker
// Underline 划线
Underline()
}
// NotesTaker 记笔记接口,装饰者接口
type NotesTaker interface {
// Booker 继承Booker接口
Booker
// TakeNotes 记笔记
TakeNotes()
}
// ConcreteUnderline 具体的划线类,实现Underliner接口
type ConcreteUnderline struct {
// Booker 书的接口对象
Booker Booker
}
// ReadingBooks ConcreteUnderline提供读书的方法,包装了Booker接口
func (underline ConcreteUnderline) Reading() {
underline.Booker.Reading()
}
// Underline 划线,实现Underliner接口
func (underline ConcreteUnderline) Underline() {
fmt.Println("我正在划线")
}
// ConcreteNotesTake 具体的记笔记类,实现NotesTaker接口
type ConcreteNotesTake struct {
// Booker 书的接口对象
Booker Booker
}
// ReadingBooks ConcreteNotesTake提供读书的方法,包装了Booker接口
func (notesTake ConcreteNotesTake) Reading() {
notesTake.Booker.Reading()
}
// Underline 划线,实现NotesTaker接口
func (notesTake ConcreteNotesTake) TakeNotes() {
fmt.Println("我正在记笔记")
}
decorator_strengthen.go
// package decorator 装饰者模式,在运行期动态地给对象添加额外的指责,比子类更灵活。第一个功能:用于增强功能的装饰模式。
package decorator
// HappinessIndex 幸福指数接口
type HappinessIndex interface {
// GetHappinessIndex 获取幸福指数
GetHappinessIndex() int
}
// MySelf 我自己,实现HappinessIndex接口
type MySelf struct{}
// GetHappinessIndex 获取幸福指数,实现HappinessIndex接口
func (myself MySelf) GetHappinessIndex() int {
return 100
}
// DrinkCoffee 喝咖啡
type DrinkCoffee struct {
// HappinessIndex 幸福指数对象
HappinessIndex HappinessIndex
}
// GetHappinessIndex 获取幸福指数,实现HappinessIndex接口
func (coffee DrinkCoffee) GetHappinessIndex() int {
return coffee.HappinessIndex.GetHappinessIndex() + 20
}
// EatFriedChicken 吃炸鸡,实现HappinessIndex接口
type EatFriedChicken struct {
// HappinessIndex 幸福指数对象
HappinessIndex HappinessIndex
}
// GetHappinessIndex 获取幸福指数,实现HappinessIndex接口
func (friedChicken EatFriedChicken) GetHappinessIndex() int {
return friedChicken.HappinessIndex.GetHappinessIndex() + 50
}
decorator_test.go
package decorator
import (
"fmt"
"testing"
)
func Test(t *testing.T) {
t.Run("decorator_strengthen: ", DecoratorStrengthen)
t.Run("decorator_add: ", DecoratorAdd)
}
func DecoratorStrengthen(t *testing.T) {
var myself, drinkCoffee, eatFriedChicken HappinessIndex
myself = &MySelf{}
fmt.Println(fmt.Sprintf("我的幸福指数是:%d", myself.GetHappinessIndex()))
drinkCoffee = &DrinkCoffee{HappinessIndex: MySelf{}}
fmt.Println(fmt.Sprintf("喝了咖啡后,我的幸福指数是:%d", drinkCoffee.GetHappinessIndex()))
eatFriedChicken = &EatFriedChicken{HappinessIndex: drinkCoffee}
fmt.Println(fmt.Sprintf("吃了炸鸡,喝了咖啡后,我的幸福指数是:%d", eatFriedChicken.GetHappinessIndex()))
fmt.Println("============")
}
func DecoratorAdd(t *testing.T) {
var book Booker
book = &Book{}
book.Reading()
fmt.Println("============")
var notesTake NotesTaker
notesTake = &ConcreteNotesTake{Booker: book}
notesTake.Reading()
notesTake.TakeNotes()
fmt.Println("============")
var Underline Underliner
Underline = &ConcreteUnderline{Booker: book}
Underline.Reading()
Underline.Underline()
}
8. 门面模式
facade.go
// package facade 门面模式
package facade
import "fmt"
// RegisterFacade 注册门面
type RegisterFacade struct {
// IUser 组合用户接口
IUser
// IVirtualAccount 组合虚拟账户接口
IVirtualAccount
// ICoupon 组合优惠券接口
ICoupon
}
// Register 注册
func (facade RegisterFacade) Register(telephone string) {
// 创建对象
user := User{Telephone: telephone}
virtualAccount := &VirtualAccount{user}
coupon := &Coupon{user}
// 创建用户
user.CreateUser()
// 创建虚拟账户
virtualAccount.CreateVirtualAcount()
// 对新账户发放优惠券
coupon.IssueCoupons()
}
// IUser 用户接口
type IUser interface {
// CreateUser 创建用户
CreateUser()
}
// IVirtualAccount 虚拟账户接口
type IVirtualAccount interface {
// CreateVirtualAcount 创建虚拟账户
CreateVirtualAcount()
}
// ICoupon 优惠券接口
type ICoupon interface {
// IssueCoupons 发放优惠券接口
IssueCoupons()
}
// User 用户,实现用户接口
type User struct {
// Telephone 电话号码
Telephone string
}
// CreateUser 创建用户
func (user User) CreateUser() {
fmt.Println(fmt.Sprintf("创建了手机号码为%s的账户", user.Telephone))
}
// VirtualAccount 虚拟账户,实现虚拟账户接口
type VirtualAccount struct {
// User 虚拟账户嵌套用户
User
}
func (virtualAccount VirtualAccount) CreateVirtualAcount() {
fmt.Println(fmt.Sprintf("为手机号码为%s的用户创建虚拟钱包账户", virtualAccount.Telephone))
}
// Coupon 优惠券,实现优惠券接口
type Coupon struct {
// User 优惠券嵌套用户
User
}
func (coupon Coupon) IssueCoupons() {
fmt.Println(fmt.Sprintf("为手机号码为%s的用户发放优惠券", coupon.Telephone))
}
facade_test.go
package facade
import "testing"
func Test(t *testing.T) {
t.Run("facade", RegisterUser)
}
func RegisterUser(t *testing.T) {
facade := RegisterFacade{}
facade.Register("18618193858")
}
factory.go
// package factory 工厂方法模式
package factory
import "fmt"
//AppleFactory 苹果工厂
type AppleFactory struct{}
//BananaFactory 香蕉工厂
type BananaFactory struct{}
//OrangeFactory 橘子工厂
type OrangeFactory struct{}
// CreateFruit 苹果工厂生产苹果
func (appleFactory AppleFactory) CreateFruit() Fruit {
return &Apple{}
}
// CreateFruit 香蕉工厂生产香蕉
func (bananaFactory BananaFactory) CreateFruit() Fruit {
return &Banana{}
}
// CreateFruit 橘子工厂生产橘子
func (orangeFactory OrangeFactory) CreateFruit() Fruit {
return &Orange{}
}
// Fruit 水果接口
type Fruit interface {
// Eat 吃水果
Eat()
}
// Apple 苹果,实现Fruit接口
type Apple struct{}
// Banana 香蕉,实现Fruit接口
type Banana struct{}
// Orange 橘子,实现Fruit接口
type Orange struct{}
// Eat 吃苹果
func (apple Apple) Eat() {
fmt.Println("吃苹果")
}
// Eat 吃香蕉
func (banana Banana) Eat() {
fmt.Println("吃香蕉")
}
// Eat 吃橘子
func (orange Orange) Eat() {
fmt.Println("吃橘子")
}
factory_test.go
package factory
import "testing"
func Test(t *testing.T) {
t.Run("factory: ", ProduceFruitAndEat)
}
func ProduceFruitAndEat(t *testing.T) {
appleFactory := &AppleFactory{}
bananaFactory := &BananaFactory{}
orangeFactory := &OrangeFactory{}
var apple, banana, orange Fruit
apple = appleFactory.CreateFruit()
apple.Eat()
banana = bananaFactory.CreateFruit()
banana.Eat()
orange = orangeFactory.CreateFruit()
orange.Eat()
}
10. 过滤器模式
filter.go
/*
package filter 过滤器模式,责任链模式的一种。
每个filter都需要验证,完全验证通过才会放行,去执行业务逻辑
一旦有filter验证不通过,则立刻退出
适合处理参数校验,权限校验,记录日志,准备相关资源等场景
*/
package filter
import (
"context"
"fmt"
"strings"
)
// Context 过滤器上下文
type Context struct {
// context.Context 嵌套基础库
context.Context
// key 每个过滤器的key
key string
}
// HandleFunc 定义别名:过滤器函数
type HandlerFunc func(ctx Context, params ...interface{}) error
// HandlersChain 过滤器责任链
type HandlersChain []HandlerFunc
// Filter 过滤器接口
type Filter interface {
DoFilter() error
}
// FilterImpl 实际的过滤器,封装了过滤器上下文、过滤器责任链
type FilterImpl struct {
// Ctx 过滤器上下文
Ctx Context
// Chain 过滤器责任链
Chain HandlersChain
}
// DoFilter 执行过滤器,FilterImpl实现Filter接口
func (myFilter *FilterImpl) DoFilter() error {
for _, handler := range myFilter.Chain {
err := handler(myFilter.Ctx)
if err != nil {
fmt.Println(fmt.Sprintf("filter fail key=%s, err = %v", myFilter.Ctx.key, err))
return err
}
}
return nil
}
//NewFilter 创建过滤器
func NewFilter(ctx Context, handlers ...HandlerFunc) Filter {
return &FilterImpl{
Ctx: ctx,
Chain: handlers,
}
}
/**********过滤器使用***********/
//ParamFilter 参数过滤器接口
type ParamFilter interface {
// DoParamFilter 执行参数过滤
DoParamFilter() error
}
// CommentParamFilter 评论参数过滤器,实现ParamFilter接口
type CommentParamFilter struct {
CommentInfo
}
// UpParamFilter 点赞参数过滤器,实现ParamFilter接口
type UpParamFilter struct {
UpInfo
}
// DoParamFilter 评论参数过滤器,实现参数过滤方法
func (cpf CommentParamFilter) DoParamFilter() error {
myContext := Context{
Context: context.TODO(),
key: "评论参数过滤器",
}
cf := NewFilter(
myContext,
validateComment1(myContext, cpf.CommentInfo),
validateComment2(myContext, cpf.CommentInfo),
)
return cf.DoFilter()
}
// validateComment1 评论参数校验方法1
func validateComment1(ctx Context, info CommentInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if info.ArticleID == 0 {
return fmt.Errorf("当前评论无文章id,不允许评论")
}
return nil
}
}
// validateComment2 评论参数校验方法2
func validateComment2(ctx Context, info CommentInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if len(info.Content) == 0 || len(strings.Trim(info.Content, " ")) == 0 {
return fmt.Errorf("当前评论无内容,不允许评论")
}
return nil
}
}
// DoParamFilter 点赞参数过滤器,实现参数过滤方法
func (upf UpParamFilter) DoParamFilter() error {
myContext := Context{
Context: context.TODO(),
key: "点赞参数过滤器",
}
cf := NewFilter(
myContext,
validateUp1(myContext, upf.UpInfo),
validateUp2(myContext, upf.UpInfo),
)
return cf.DoFilter()
}
// validateUp1 点赞参数校验方法1
func validateUp1(ctx Context, info UpInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if info.CommenID == 0 {
return fmt.Errorf("当前点赞无评论id,不允许点赞")
}
return nil
}
}
// validateUp2 点赞参数校验方法2
func validateUp2(ctx Context, info UpInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if info.UserID == 0 {
return fmt.Errorf("当前点赞无用户id,不允许点赞")
}
return nil
}
}
// CommentInfo 评论
type CommentInfo struct {
// Content 评论内容
Content string
// ArticleID 文章ID
ArticleID uint64
}
// UpInfo 点赞
type UpInfo struct {
// CommenID 评论ID
CommenID uint64
// UserID 点赞人的用户ID
UserID uint64
}
filter_test.go
package filter
import "testing"
func Test(t *testing.T) {
t.Run("comment_filter1: ", CommentFilter1)
t.Run("comment_filter2: ", CommentFilter2)
t.Run("comment_filter3: ", CommentFilter3)
t.Run("up_filter1: ", UpFilter1)
t.Run("up_filter2: ", UpFilter2)
}
func CommentFilter1(t *testing.T) {
//构造过滤器信息
info := CommentInfo{
Content: "",
ArticleID: 1,
}
//执行过滤器
var commentFilter CommentParamFilter
commentFilter = CommentParamFilter{info}
commentFilter.DoParamFilter()
}
func CommentFilter2(t *testing.T) {
//构造过滤器信息
info := CommentInfo{
Content: "太可怕了",
ArticleID: 0,
}
//执行过滤器
var commentFilter CommentParamFilter
commentFilter = CommentParamFilter{info}
commentFilter.DoParamFilter()
}
func CommentFilter3(t *testing.T) {
//构造过滤器信息
info := CommentInfo{
Content: " ",
ArticleID: 1234,
}
//执行过滤器
var commentFilter CommentParamFilter
commentFilter = CommentParamFilter{info}
commentFilter.DoParamFilter()
}
func UpFilter1(t *testing.T) {
//构造过滤器信息
info := UpInfo{
CommenID: 0,
UserID: 6379,
}
//执行过滤器
var upFilter UpParamFilter
upFilter = UpParamFilter{info}
upFilter.DoParamFilter()
}
func UpFilter2(t *testing.T) {
//构造过滤器信息
info := UpInfo{
CommenID: 5678,
UserID: 0,
}
//执行过滤器
var upFilter UpParamFilter
upFilter = UpParamFilter{info}
upFilter.DoParamFilter()
}
filter_test.go
filter.go
/*
package filter 过滤器模式,责任链模式的一种。
每个filter都需要验证,完全验证通过才会放行,去执行业务逻辑
一旦有filter验证不通过,则立刻退出
适合处理参数校验,权限校验,记录日志,准备相关资源等场景
*/
package filter
import (
"context"
"fmt"
"strings"
)
// Context 过滤器上下文
type Context struct {
// context.Context 嵌套基础库
context.Context
// key 每个过滤器的key
key string
}
// HandleFunc 定义别名:过滤器函数
type HandlerFunc func(ctx Context, params ...interface{}) error
// HandlersChain 过滤器责任链
type HandlersChain []HandlerFunc
// Filter 过滤器接口
type Filter interface {
DoFilter() error
}
// FilterImpl 实际的过滤器,封装了过滤器上下文、过滤器责任链
type FilterImpl struct {
// Ctx 过滤器上下文
Ctx Context
// Chain 过滤器责任链
Chain HandlersChain
}
// DoFilter 执行过滤器,FilterImpl实现Filter接口
func (myFilter *FilterImpl) DoFilter() error {
for _, handler := range myFilter.Chain {
err := handler(myFilter.Ctx)
if err != nil {
fmt.Println(fmt.Sprintf("filter fail key=%s, err = %v", myFilter.Ctx.key, err))
return err
}
}
return nil
}
//NewFilter 创建过滤器
func NewFilter(ctx Context, handlers ...HandlerFunc) Filter {
return &FilterImpl{
Ctx: ctx,
Chain: handlers,
}
}
/**********过滤器使用***********/
//ParamFilter 参数过滤器接口
type ParamFilter interface {
// DoParamFilter 执行参数过滤
DoParamFilter() error
}
// CommentParamFilter 评论参数过滤器,实现ParamFilter接口
type CommentParamFilter struct {
CommentInfo
}
// UpParamFilter 点赞参数过滤器,实现ParamFilter接口
type UpParamFilter struct {
UpInfo
}
// DoParamFilter 评论参数过滤器,实现参数过滤方法
func (cpf CommentParamFilter) DoParamFilter() error {
myContext := Context{
Context: context.TODO(),
key: "评论参数过滤器",
}
cf := NewFilter(
myContext,
validateComment1(myContext, cpf.CommentInfo),
validateComment2(myContext, cpf.CommentInfo),
)
return cf.DoFilter()
}
// validateComment1 评论参数校验方法1
func validateComment1(ctx Context, info CommentInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if info.ArticleID == 0 {
return fmt.Errorf("当前评论无文章id,不允许评论")
}
return nil
}
}
// validateComment2 评论参数校验方法2
func validateComment2(ctx Context, info CommentInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if len(info.Content) == 0 || len(strings.Trim(info.Content, " ")) == 0 {
return fmt.Errorf("当前评论无内容,不允许评论")
}
return nil
}
}
// DoParamFilter 点赞参数过滤器,实现参数过滤方法
func (upf UpParamFilter) DoParamFilter() error {
myContext := Context{
Context: context.TODO(),
key: "点赞参数过滤器",
}
cf := NewFilter(
myContext,
validateUp1(myContext, upf.UpInfo),
validateUp2(myContext, upf.UpInfo),
)
return cf.DoFilter()
}
// validateUp1 点赞参数校验方法1
func validateUp1(ctx Context, info UpInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if info.CommenID == 0 {
return fmt.Errorf("当前点赞无评论id,不允许点赞")
}
return nil
}
}
// validateUp2 点赞参数校验方法2
func validateUp2(ctx Context, info UpInfo) HandlerFunc {
return func(ctx Context, params ...interface{}) error {
if info.UserID == 0 {
return fmt.Errorf("当前点赞无用户id,不允许点赞")
}
return nil
}
}
// CommentInfo 评论
type CommentInfo struct {
// Content 评论内容
Content string
// ArticleID 文章ID
ArticleID uint64
}
// UpInfo 点赞
type UpInfo struct {
// CommenID 评论ID
CommenID uint64
// UserID 点赞人的用户ID
UserID uint64
}
filter_test.go
package filter
import "testing"
func Test(t *testing.T) {
t.Run("comment_filter1: ", CommentFilter1)
t.Run("comment_filter2: ", CommentFilter2)
t.Run("comment_filter3: ", CommentFilter3)
t.Run("up_filter1: ", UpFilter1)
t.Run("up_filter2: ", UpFilter2)
}
func CommentFilter1(t *testing.T) {
//构造过滤器信息
info := CommentInfo{
Content: "",
ArticleID: 1,
}
//执行过滤器
var commentFilter CommentParamFilter
commentFilter = CommentParamFilter{info}
commentFilter.DoParamFilter()
}
func CommentFilter2(t *testing.T) {
//构造过滤器信息
info := CommentInfo{
Content: "太可怕了",
ArticleID: 0,
}
//执行过滤器
var commentFilter CommentParamFilter
commentFilter = CommentParamFilter{info}
commentFilter.DoParamFilter()
}
func CommentFilter3(t *testing.T) {
//构造过滤器信息
info := CommentInfo{
Content: " ",
ArticleID: 1234,
}
//执行过滤器
var commentFilter CommentParamFilter
commentFilter = CommentParamFilter{info}
commentFilter.DoParamFilter()
}
func UpFilter1(t *testing.T) {
//构造过滤器信息
info := UpInfo{
CommenID: 0,
UserID: 6379,
}
//执行过滤器
var upFilter UpParamFilter
upFilter = UpParamFilter{info}
upFilter.DoParamFilter()
}
func UpFilter2(t *testing.T) {
//构造过滤器信息
info := UpInfo{
CommenID: 5678,
UserID: 0,
}
//执行过滤器
var upFilter UpParamFilter
upFilter = UpParamFilter{info}
upFilter.DoParamFilter()
}