设计模式面试题go语言 go语言面试100题( 三 )


通常,使用 interface{} 是相对危险的 。使用更多受限制的类型总是更安全,因为可以在编译时而不是运行时发现问题 。
泛型通过允许类型具有类型参数来解决此问题:
type Stack(type T) []Tfunc (s Stack(T)) Peek() T {
return s[len(s)-1]
}
func (s *Stack(T)) Pop() {
*s = (*s)[:
len(*s)-1]
}
【设计模式面试题go语言 go语言面试100题】func (s *Stack(T)) Push(value T) {
*s =
append(*s, value)
}
这会向 Stack 添加一个类型参数 , 从而完全不需要 interface{} 。现在,当你使用 Peek() 时,返回的值已经是原始类型,并且没有机会返回错误的值类型 。这种方式更安全,更容易使用 。(译注:就是看起来更丑陋,^-^)
此外,泛型代码通常更易于编译器优化,从而获得更好的性能(以二进制大小为代价) 。如果我们对上面的非泛型代码和泛型代码进行基准测试 , 我们可以看到区别:
type MyObject struct {
X
int
}
var sink MyObjectfunc BenchmarkGo1(b *testing.B) {
for i := 0; ib.N; i++ {
var s Stack
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink = s.Peek().(MyObject)
}
}
func BenchmarkGo2(b *testing.B) {
for i := 0; ib.N; i++ {
var s Stack(MyObject)
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink = s.Peek()
}
}
结果:
BenchmarkGo1BenchmarkGo1-161283752887.0 ns/op48 B/op2 allocs/opBenchmarkGo2BenchmarkGo2-162840647941.9 ns/op24 B/op2 allocs/op
在这种情况下,我们分配更少的内存 , 同时泛型的速度是非泛型的两倍 。
合约(Contracts)
上面的堆栈示例适用于任何类型 。但是,在许多情况下,你需要编写仅适用于具有某些特征的类型的代码 。例如 , 你可能希望堆栈要求类型实现 String() 函数
列出几种软件开发中常见的设计模式并解释列出几种软件开发中常见的设计模式并解释
设计模式主要分三个类型:创建型、结构型和行为型 。
其中创建型有:
一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点
二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类 。
三、Factory Method,工厂方法:定义一个用于创建对象的接口 , 让子类决定实例化哪一个类 , Factory Method使一个类的实例化延迟到了子类 。
四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示 。
五、Prototype , 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象 。
行为型有:
六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示 。
七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新 。
八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤 。
九、Command,命令模式:将一个请求封装为一个对象 , 从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志 , 以及支持可撤销的操作 。
十、State,状态模式:允许对象在其内部状态改变时改变他的行为 。对象看起来似乎改变了他的类 。

推荐阅读