关于Golang面试宝典
最近几年,Go的热度持续飙升,国内外很多大公司都在大规模的使用Go。Google是Go语言诞生的地方,其他公司如Facebook、腾讯、阿里、字节跳动、百度、京东、小米等都在拥抱和转向Go。Go语言的开源项目也非常多,如kubernetes、docker、etcd。
随着市场对Go语言人才需求的增长,很多开发者都投入了Go语言的怀抱。本系列文章将以第一视角与大家一同开始Golang的面试之路,希望大家能够有所收获,拿下心仪的offer。
使用Go实现23种设计模式——行为型模式(下)
迭代器模式
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
适用场景
- 把在元素之间游走的责任交给迭代器,而不是集合对象
Go语言实现
type IAggregate interface {
Iterator() IIterator
}
type IIterator interface {
HasNext() bool
Current() int
Next() bool
}
type Aggregate struct {
Container []int
}
func (a *Aggregate) Iterator() IIterator {
i := new(Iterator)
i.aggregate = a
return i
}
type Iterator struct {
cursor int
aggregate *Aggregate
}
func (i *Iterator) HasNext() bool {
return i.cursor < len(i.aggregate.Container)-1
}
func (i *Iterator) Current() int {
return i.aggregate.Container[i.cursor]
}
func (i *Iterator) Next() bool {
if i.HasNext() {
i.cursor++
return true
}
return false
}
func main() {
a := &Aggregate{Container: []int{1, 2, 3, 4}}
it := a.Iterator()
for {
fmt.Printf("current: %d\n", it.Current())
if it.HasNext() {
it.Next()
} else {
break
}
}
}
迭代器模式优点
- 它支持不同的方式遍历集合对象
- 迭代器简化了聚合类
- 在同一个聚合上面可以有多个遍历
- 迭代器模式中,新增聚合类和迭代器都很方便,无需新增代码
迭代器模式缺点
- 增加新的聚合类需要增加对应新的迭代器
解释器模式
提供如何定义语言的文法,以及对语言句子的解释方法
适用场景
- 一般应用于编译器、规则引擎、正则表达式等功能
Go语言实现
type Expression interface {
Interpret(context string) bool
}
type TerminalExpression struct {
Context string
}
func (e *TerminalExpression) Interpret(context string) bool {
return strings.Contains("good", context)
}
type OrExpression struct {
Expr1 Expression
Expr2 Expression
}
func NewOrExpression(e1, e2 Expression) *OrExpression {
return &OrExpression{
Expr1: e1,
Expr2: e2,
}
}
func (e *OrExpression) Interpret(context string) bool {
return e.Expr1.Interpret(context) || e.Expr2.Interpret(context)
}
func main() {
g := &TerminalExpression{Context: "go"}
d := &TerminalExpression{Context: "god"}
o := NewOrExpression(g, d)
r := o.Interpret("god")
fmt.Println(r)
}
解释器模式优点
- 可扩展性高、灵活
- 易于实现简单的文法
解释器模式缺点
- 可使用场景少
- 复杂文法较难维护
命令模式
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开
适用场景
- 对行为进行记录、撤销、重做等处理
Go语言实现
type Order interface {
Execute()
}
type Runner struct{}
func (r *Runner) Execute() {
fmt.Println("running")
}
type Control struct {
Cmd Order
}
func (c *Control) SetCmd(cmd Order) {
c.Cmd = cmd
}
func (c *Control) Do() {
c.Cmd.Execute()
}
func main() {
c := Control{}
r := Runner{}
c.SetCmd(&r)
c.Do()
}
命令模式优点
- 通过引入中间件降低了系统的耦合度
- 扩展性良好,且满足"开闭原则"
命令模式缺点
- 每一个具体操作都需要设计一个具体命令类,增加了系统复杂度
责任链模式
将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链,直到请求被处理为止
适用场景
- 多个对象可以处理一个请求,但是具体由谁来执行在运行时自动确定
- 可动态指定一组对象处理请求或添加新的处理者
Go语言实现
type Context struct {
Data string
}
type Handle interface {
Handle(context Context)
SetNext(handle Handle)
GetNext() (next Handle, ok bool)
}
type LogHandle struct {
next Handle
}
func (h *LogHandle) Handle(c Context) {
fmt.Printf("日志:%s", c.Data)
if next, ok := h.GetNext(); ok {
next.Handle(c)
}
}
func (h *LogHandle) SetNext(next Handle) {
h.next = next
}
func (h *LogHandle) GetNext() (next Handle, ok bool) {
if h.next != nil {
return h.next, true
}
return nil, false
}
type AuthHandle struct {
next Handle
}
func (h *AuthHandle) Handle(c Context) {
fmt.Printf("权限:%s", c.Data)
if next, ok := h.GetNext(); ok {
next.Handle(c)
}
}
func (h *AuthHandle) SetNext(next Handle) {
h.next = next
}
func (h *AuthHandle) GetNext() (next Handle, ok bool) {
if h.next != nil {
return h.next, true
}
return nil, false
}
func main() {
auth := AuthHandle{}
log := LogHandle{}
log.SetNext(&auth)
context := Context{Data: "test"}
log.Handle(context)
}
责任链模式优点
- 降低了对象间的耦合度
- 增强了系统的可扩展性
- 增强了给对象指派职责的灵活性
- 简化了对象间的连接
责任链模式缺点
- 不能保证每个请求一定被处理
- 责任链建立的合理性靠客户端保证,增加了客户端的复杂性