技术总结|十分钟了解Go设计模式

设计模式是软件设计中常见的解决方案,本文介绍两种设计模式类型。
(1)创建型模式提供对象创建机制,以提高灵活性和重用现有代码,包括:

  • 单例模式
  • 工厂方法
  • 抽象工厂
  • 建造者模式
  • 原型模式

(2)行为型模式关注对象之间的有效通信和责任分配,包括:

  • 观察者模式
  • 命令模式
  • 迭代器模式
  • 策略模式
  • 责任链模式
  • 访问者模式

1、单例模式

单例是一种创建型设计模式,可让您确保一个类只有一个实例,同时提供对该实例的全局访问点。

package singleton

import (
    "sync"
)

type singleton struct {
}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

2、工厂方法

工厂方法是一种创建型设计模式,它提供用于在超类中创建对象的接口,但允许子类更改将要创建的对象的类型。

package simplefactory

import "fmt"

type API interface {
 Say(name stringstring
}

func NewAPI(t int) API {
 if t == 1 {
  return &hiAPI{}
 } else if t == 2 {
  return &helloAPI{}
 }
 return nil
}

type hiAPI struct{}

func (*hiAPI) Say(name string) string {
 return fmt.Sprintf("Hi, %s", name)
}

type helloAPI struct{}

func (*helloAPI) Say(name string) string {
 return fmt.Sprintf("Hello, %s", name)
}

3、抽象工厂

抽象工厂是一种创建型设计模式,可让您在不指定具体类的情况下生成相关对象系列。
抽象工厂定义了一个用于创建所有不同产品的接口,但将实际的产品创建留给了具体的工厂类,每种工厂类型对应的产品品种。

// 抽象工厂接口
package main

import "fmt"

type iSportsFactory interface {
    makeShoe() iShoe
}

func getSportsFactory(brand string) (iSportsFactory, error) {
    if brand == "adidas" {
        return &adidas{}, nil
    }

    if brand == "nike" {
        return &nike{}, nil
    }

    return nil, fmt.Errorf("Wrong brand type passed")
}

// 具体工厂类
package main

type adidas struct {
}

func (a *adidas) makeShoe() iShoe {
    return &adidasShoe{
        shoe: shoe{
            logo: "adidas",
            size: 14,
        },
    }
}

// 具体的产品
package main

type iShoe interface {
    setLogo(logo string)
    setSize(size int)
    getLogo() string
    getSize() int
}

type shoe struct {
    logo string
    size int
}

func (s *shoe) setLogo(logo string) {
    s.logo = logo
}

func (s *shoe) getLogo() string {
    return s.logo
}

func (s *shoe) setSize(size int) {
    s.size = size
}

func (s *shoe) getSize() int {
    return s.size
}

4、建造者模式

建造者模式是一种创建型设计模式,可让您逐步构建复杂的对象,该模式允许您使用相同的构造代码生成对象的不同类型和表示。
当所需的产品很复杂并且需要多个步骤才能完成时,使用构建器模式,在这种情况下,多个构造方法会比单个庞大的构造函数更简单。
建造者模式将一堆接口定义好,开发者只需要自己注册按照步骤拆分对应接口的具体类即可。

package builder

type Builder interface {
 Part1()
 Part2()
 Part3()
}

type Director struct {
 builder Builder
}

// NewDirector ...
func NewDirector(builder Builder) *Director {
 return &Director{
  builder: builder,
 }
}

//Construct Product
func (d *Director) Construct() {
 d.builder.Part1()
 d.builder.Part2()
 d.builder.Part3()
}

type Builder1 struct {
 result string
}

func (b *Builder1) Part1() {
 b.result += "1"
}

func (b *Builder1) Part2() {
 b.result += "2"
}

func (b *Builder1) Part3() {
 b.result += "3"
}

func (b *Builder1) GetResult() string {
 return b.result
}

type Builder2 struct {
 result int
}

func (b *Builder2) Part1() {
 b.result += 1
}

func (b *Builder2) Part2() {
 b.result += 2
}

func (b *Builder2) Part3() {
 b.result += 3
}

func (b *Builder2) GetResult() int {
 return b.result
}

5、原型模式

原型是一种创造型设计模式,它允许克隆对象,甚至是复杂的对象,而无需耦合到它们的特定类。

// 定义原型接口
package main

type inode interface {
    print(string)
    clone() inode
}

// 具体文件的类
package main

import "fmt"

type file struct {
    name string
}

func (f *file) print(indentation string) {
    fmt.Println(indentation + f.name)
}

func (f *file) clone() inode {
    return &file{name: f.name + "_clone"}
}

// 具体文件夹的类
package main

import "fmt"

type folder struct {
    children []inode
    name      string
}

func (f *folder) print(indentation string) {
    fmt.Println(indentation + f.name)
    for _, i := range f.children {
        i.print(indentation + indentation)
    }
}

func (f *folder) clone() inode {
    cloneFolder := &folder{name: f.name + "_clone"}
    var tempChildren []inode
    for _, i := range f.children {
        copy := i.clone()
        tempChildren = append(tempChildren, copy)
    }
    cloneFolder.children = tempChildren
    return cloneFolder
}

// 主方法
package main

import "fmt"

func main() {
    file1 := &file{name: "File1"}
    file2 := &file{name: "File2"}
    file3 := &file{name: "File3"}

    folder1 := &folder{
        children: []inode{file1},
        name:      "Folder1",
    }

    folder2 := &folder{
        children: []inode{folder1, file2, file3},
        name:      "Folder2",
    }
    fmt.Println("nPrinting hierarchy for Folder2")
    folder2.print("  ")

    cloneFolder := folder2.clone()
    fmt.Println("nPrinting hierarchy for clone Folder")
    cloneFolder.print("  ")
}

6、观察者模式

观察者模式是一种行为设计模式,它允许一些对象通知其他对象其状态的变化,观察者模式为任何实现订阅者接口的对象提供了订阅和取消订阅这些事件的方法。

package observer

type subject interface {
    register(Observer observer)
    deregister(Observer observer)
    notifyAll()
}

// 消费者
type observer interface {
    update(string)
    getID() string
}

type item struct {
    observerList []observer
    name         string
    inStock      bool
}

func newItem(name string) *item {
    return &item{
        name: name,
    }
}

func (i *item) updateAvailability() {
    fmt.Printf("Item %s is now in stockn", i.name)
    i.inStock = true
    i.notifyAll()
}

func (i *item) register(o observer) {
    i.observerList = append(i.observerList, o)
}

func (i *item) deregister(o observer) {
    i.observerList = removeFromslice(i.observerList, o)
}

func (i *item) notifyAll() {
    for _, observer := range i.observerList {
        observer.update(i.name)
    }
}

func removeFromslice(observerList []observer, observerToRemove observer) []observer {
    observerListLength := len(observerList)
    for i, observer := range observerList {
        if observerToRemove.getID() == observer.getID() {
            observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
            return observerList[:observerListLength-1]
        }
    }
    return observerList
}

type customer struct {
    id string
}

func (c *customer) update(itemName string) {
    fmt.Printf("Sending email to customer %s for item %sn", c.id, itemName)
}

func (c *customer) getID() string {
    return c.id
}

func main() {
    shirtItem := newItem("Nike Shirt")

    observerFirst := &customer{id: "abc@gmail.com"}
    observerSecond := &customer{id: "xyz@gmail.com"}

    shirtItem.register(observerFirst)
    shirtItem.register(observerSecond)

    shirtItem.updateAvailability()
}

7、命令模式

命令模式是将请求或简单操作转换为对象的行为设计模式,转换允许延迟或远程执行命令、存储命令历史记录等。

package command

import "fmt"

type Command interface {
 Execute()
}

type StartCommand struct {
 mb *MotherBoard
}

func NewStartCommand(mb *MotherBoard) *StartCommand {
 return &StartCommand{
  mb: mb,
 }
}

func (c *StartCommand) Execute() {
 c.mb.Start()
}

type RebootCommand struct {
 mb *MotherBoard
}

func NewRebootCommand(mb *MotherBoard) *RebootCommand {
 return &RebootCommand{
  mb: mb,
 }
}

func (c *RebootCommand) Execute() {
 c.mb.Reboot()
}

8、迭代器模式

迭代器是一种行为设计模式,允许在不暴露其内部细节的情况下顺序遍历复杂的数据结构

type collection interface {
    createIterator() iterator
}

type userCollection struct {
    users []*user
}

func (u *userCollection) createIterator() iterator {
    return &userIterator{
        users: u.users,
    }
}

type iterator interface {
    hasNext() bool
    getNext() *user
}

type userIterator struct {
    index int
    users []*user
}

func (u *userIterator) hasNext() bool {
    if u.index < len(u.users) {
        return true
    }
    return false

}
func (u *userIterator) getNext() *user {
    if u.hasNext() {
        user := u.users[u.index]
        u.index++
        return user
    }
    return nil
}

type user struct {
    name string
    age  int
}

func main() {
    user1 := &user{
        name: "a",
        age:  30,
    }
    user2 := &user{
        name: "b",
        age:  20,
    }

    userCollection := &userCollection{
        users: []*user{user1, user2},
    }

    iterator := userCollection.createIterator()

    for iterator.hasNext() {
        user := iterator.getNext()
        fmt.Printf("User is %+vn", user)
    }
}

9、策略模式

策略模式是一种行为设计模式,它将一组行为转化为对象,并使它们在原始上下文对象中可以互换,称为上下文的原始对象持有对策略对象的引用,并委托它执行行为。
为了改变上下文执行其工作的方式,其他对象可能会用另一个对象替换当前链接的策略对象。

type Payment struct {
 context  *PaymentContext
 strategy PaymentStrategy
}

type PaymentContext struct {
 Name, CardID string
 Money        int
}

func NewPayment(name, cardid string, money int, strategy PaymentStrategy) *Payment {
 return &Payment{
  context: &PaymentContext{
   Name:   name,
   CardID: cardid,
   Money:  money,
  },
  strategy: strategy,
 }
}

func (p *Payment) Pay() {
 p.strategy.Pay(p.context)
}

type PaymentStrategy interface {
 Pay(*PaymentContext)
}

type Cash struct{}

func (*Cash) Pay(ctx *PaymentContext) {
 fmt.Printf("Pay $%d to %s by cash", ctx.Money, ctx.Name)
}

type Bank struct{}

func (*Bank) Pay(ctx *PaymentContext) {
 fmt.Printf("Pay $%d to %s by bank account %s", ctx.Money, ctx.Name, ctx.CardID)
}

10、责任链模式

责任链是一种行为设计模式,它允许沿着潜在处理程序链传递请求,直到其中一个处理程序处理请求。
该模式允许多个对象处理请求,而无需将发送者类耦合到接收者的具体类,该链可以在运行时与任何遵循标准处理程序接口的处理程序动态组合。

// department
type department interface {
    execute(*patient)
    setNext(department)
}

// reception
type reception struct {
    next department
}

func (r *reception) execute(p *patient) {
    if p.registrationDone {
        fmt.Println("Patient registration already done")
        r.next.execute(p)
        return
    }
    fmt.Println("Reception registering patient")
    p.registrationDone = true
    r.next.execute(p)
}

func (r *reception) setNext(next department) {
    r.next = next
}

// doctor
type doctor struct {
    next department
}

func (d *doctor) execute(p *patient) {
    if p.doctorCheckUpDone {
        fmt.Println("Doctor checkup already done")
        d.next.execute(p)
        return
    }
    fmt.Println("Doctor checking patient")
    p.doctorCheckUpDone = true
    d.next.execute(p)
}

func (d *doctor) setNext(next department) {
    d.next = next
}

type cashier struct {
    next department
}

func (c *cashier) execute(p *patient) {
    if p.paymentDone {
        fmt.Println("Payment Done")
    }
    fmt.Println("Cashier getting money from patient patient")
}

func (c *cashier) setNext(next department) {
    c.next = next
}

type patient struct {
    name              string
    registrationDone  bool
    doctorCheckUpDone bool
    medicineDone      bool
    paymentDone       bool
}

func main() {
    cashier := &cashier{}

    doctor := &doctor{}
    doctor.setNext(cashier)

    reception := &reception{}
    reception.setNext(doctor)

    patient := &patient{name: "abc"}
    reception.execute(patient)
}

11、访问者模式

访问者模式是一种行为设计模式,允许在不更改任何现有代码的情况下向现有类层次结构添加新行为。

type SchemaVisitor interface {
 VisitArray(*Array)
 VisitMap(*Map)
 VisitPrimitive(*Primitive)
 VisitKind(*Kind)
 VisitReference(Reference)
}

//Schema is the base definition of an openapi type.
type Schema interface {
 //Giving a visitor here will let you visit the actual type.
 Accept(SchemaVisitor)

 //Pretty print the name of the type.
 GetName() string
 //Describes how to access this field.
 GetPath() *Path
 //Describes the field.
 GetDescription() string
 //Returns type extensions.
 GetExtensions() map[string]interface{}
}

///k8s.io/kubernetes/pkg/kubectl/resource/builder.go
func (b *Builder) visitByName() *Result {
 ...
 visitors := []Visitor{}
 for _, name := range b.names {
  info := NewInfo(client, mapping, selectorNamespace, name, b.export)
  visitors = append(visitors, info)
 }
 result.visitor = VisitorList(visitors)
 result.sources = visitors
 return result
}

参考

(1)https://www.runoob.com/design-pattern/strategy-pattern.html
(2)https://aly.arriqaaq.com/golang-design-patterns/



原文始发于微信公众号(周末程序猿):技术总结|十分钟了解Go设计模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/169401.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!