关于Golang面试宝典

最近几年,Go的热度持续飙升,国内外很多大公司都在大规模的使用Go。Google是Go语言诞生的地方,其他公司如Facebook、腾讯、阿里、字节跳动、百度、京东、小米等都在拥抱和转向Go。Go语言的开源项目也非常多,如kubernetes、docker、etcd。

随着市场对Go语言人才需求的增长,很多开发者都投入了Go语言的怀抱。本系列文章将以第一视角与大家一同开始Golang的面试之路,希望大家能够有所收获,拿下心仪的offer。

使用Go实现23种设计模式——行为型模式(中)

观察者模式

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

适用场景

  1. 对一个对象状态或数据的更新需要其他对象同步更新,或者一个对象的更新需要依赖另一个对象的更新
  2. 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送等

Go语言实现

type Event struct {
	Data string
}

type IObServer interface {
	Update(event *Event)
}

type ISubject interface {
	Register(server IObServer)
	Remove(server IObServer)
	Notify(event *Event)
}

type ObServer struct {
	Id int
}

func (s *ObServer) Update(event *Event) {
	fmt.Printf("observer %d msg: %s", s.Id, event.Data)
}

type Subject struct {
	ObServers map[IObServer]struct{}
}

func NewSubject() *Subject {
	return &Subject{ObServers: make(map[IObServer]struct{})}
}

func (s *Subject) Register(server IObServer) {
	s.ObServers[server] = struct{}{}
}

func (s *Subject) Remove(server IObServer) {
	delete(s.ObServers, server)
}

func (s *Subject) Notify(event *Event) {
	for ob, _ := range s.ObServers {
		ob.Update(event)
	}
}

func main() {
	s := NewSubject()

	o1 := ObServer{Id: 1}
	o2 := ObServer{Id: 2}

	s.Register(&o1)
	s.Register(&o2)

	s.Notify(&Event{Data: "123"})
}
复制代码

观察者模式优点

  1. 你无需修改被观察者代码就能引入新的观察者
  2. 你可以在运行时建立对象之间的联系

观察者模式缺点

  1. 观察者的通知顺序是随机的

备忘录模式

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态

适用场景

  1. 回退场景、撤销重做
  2. 备份与还原、快照与恢复

Go语言实现

type Memento struct {
	State string
}

func (m *Memento) SetState(s string) {
	m.State = s
}

func (m *Memento) GetState() string {
	return m.State
}

func (m *Memento) CreateMemento() *Memento {
	return &Memento{State: m.State}
}

type CareTaker struct {
	memento *Memento
}

func (c *CareTaker) GetMemento() *Memento {
	return c.memento
}

func (c *CareTaker) SetMemento(m *Memento) {
	c.memento = m
}

func main() {
	o := Memento{State: "running"}
	fmt.Printf("当前状态: %s", o.State)

	c := new(CareTaker)
	c.SetMemento(o.CreateMemento())

	o.SetState("finish")
	fmt.Printf("修改后的状态: %s", o.State)

	o.SetState(c.GetMemento().GetState())
	fmt.Printf("还原后的状态: %s", o.State)
}
复制代码

备忘录模式优点

  1. 能够很方便的回到某个历史状态
  2. 实现了信息的封装,使用方不需要关心状态的保存细节

备忘录模式缺点

  1. 消耗资源

中介者模式

定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解

适用场景

  1. 系统中的对象之间存在复杂的引用关系,如相互依赖
  2. 存在交互的公共行为,如果需要改变行为可增加中介者类

Go语言实现

type Item interface {
	SendMsg(msg string)
	GetMsg(msg string)
}

type User struct {
	mediator *Mediator
}

func (u *User) SendMsg(msg string) {
	u.mediator.ForwardMsg(u, msg)
}

func (u *User) GetMsg(msg string) {
	fmt.Printf("user get msg: %s: ", msg)
}

type Server struct {
	mediator *Mediator
}

func (s *Server) SendMsg(msg string) {
	s.mediator.ForwardMsg(s, msg)
}

func (s *Server) GetMsg(msg string) {
	fmt.Printf("server get msg: %s", msg)
}

type Mediator struct {
	User
	Server
}

func (m *Mediator) ForwardMsg(item Item, msg string) {
	switch item.(type) {
	case *User:
		m.Server.GetMsg(msg)
		break
	case *Server:
		m.User.GetMsg(msg)
		break
	default:
		fmt.Printf("Error")
	}
}

func main() {
	mediator := Mediator{}

	u := User{}
	s := Server{}

	mediator.User = u
	mediator.Server = s

	u.SendMsg("Hello")
	s.SendMsg("Hi")
}
复制代码

中介者模式优点

  1. 减少类间的依赖,降低类间耦合

中介者模式缺点

  1. 当同事类越多时中介者就越臃肿