GO是否是面向对象的语言?程序员
GO做者如是说:“是,也不是。”编程
正如前面所说:GO是一种面向类型的语言,它有类型和方法,但没有类的概念,程序员能够用一种面向对象的风格(或者说是方式)来编程,下面咱们从封装性、继承性和多态性三大面向对象的特性谈谈GO语言iphone
一、封装性ide
面向对象的语言中,“类”是基本单位,它把属性、方法局限在“类”中,并对外提供公共方法让使用者操做对象。固然这一过程离不开修饰符:public、protected、private等。函数
GO语言如何实现封装性呢?它是经过结构体(struct)和为类型添加方法的方式实现的。测试
例如,封装一个矩形(Rect)类,试想调用者会对矩形类作什么操做呢?无非就是看看它的面积、周长之类的信息,那么按照面向对象的编程思想来讲,只要向使用者暴露getArea()、getPerimeter()方法便可,使用者无须接触到矩形的长和宽。ui
/**spa * 定义一个结构体,里面有两个成员length和width3d */orm type Rect struct { length, width int } |
接下来为结构体定义两个方法getArea()和getPerimeter(),分别用来读取矩形的面积和周长
/** * 获取矩形的面积 */ func (r *Rect) GetArea() int { return r.length * r.width } /** * 获取矩形的周长 */ func (r *Rect) GetPerimeter() int { return (r.length + r.width) * 2 } |
为了让该包以外的函数调用到GetArea()和GetPerimeter(),因此这里函数的首字母大写。同时为告终构体初始化更面向对象些,再定义一个用于初始化结构体的方法NewRect()
/** * 初始化结构体Rect */ func NewRect(length, width int) *Rect { return &Rect{length, width} } |
通过这样的封装,使用者能够以面向对象的方式调用Rect了 :)
/** * 使用者先引入Rect.go的路径 */ import ( "cube" "fmt" ) /** * 经过cube调用NewRect()生成*Rect对象 */ func main() { r := cube.NewRect(10, 20) fmt.Println("面积:", r.GetArea(), " 周长:", r.GetPerimeter()) } |
【备注】:
Rect.go和测试main.go路径结构以下
其中Rect.go所属包为cube、main.go所属包为main
执行程序,运行结果以下:
二、继承性
rect结构体定义两个方法,分别用于获取面积和周长,cube结构体也定义了两个方法,一个是获取体积,另外一个重写父结构体rect的获取周长:
(1)在cube目录下建立rect.go文件,里面写rect代码
// 让rect结构体在cube包内 package cube // 定义rect结构体 type rect struct{ length, width int } /** * 获取矩形的面积 */ func (r Rect) GetArea() int { return r.length * r.width } /** * 获取矩形的周长 */ func (r Rect) GetPerimeter() int { return (r.length + r.width) * 2 } |
(2)在cube目录下建立cube.go文件,里面写cube代码
// 让Cube结构体在cube包内 package cube // 因为Cube结构体须要对外,因此首字母大写 type Cube struct { Rect // 这里经过嵌套结构体实现GO的继承 height int } /** * 获取立方体的体积 */ func (c Cube) GetVolume() int { return c.Rect.length * c.Rect.width * c.height } /** * 重写父类获取周长方法 */ func (c Cube) GetPerimeter() int { return (c.Rect.length + c.Rect.width + c.height) * 4 } /** * 为了更象面向对象编程些,这里定义了一个方法获取Cube对象 */ func NewCube(length, width, height int) Cube { return Cube{Rect: Rect{length, width}, height: height} } |
(3)在src目录下建立main.go文件,该文件与cube目录同级,里面写测试代码
// 让main()方法的包为main package main import ( "cube" // 因为要用到上面定义的Cube结构体,因此须要引入Cube结构体所属包 "fmt" ) func main() { var c cube.Cube = cube.NewCube(10, 20, 30) // 经过包名调用cube.go定义的对外方法NewCube() fmt.Println("面积:", c.GetArea(), ",体积:", c.GetVolume()) // 经过变量c调用相应方法 fmt.Println("周长:", c.GetPerimeter()) } |
执行go run main.go,获得执行结果:
从运行结果能够看到,尽管Cube没有定义GetArea()方法,但经过c.GetArea()的确调用到了同时并打印出结果;因为Cube重写了GetPerimeter()方法,从结果来看c.GetPerimeter()执行的是Cube的GetPerimeter()就去。
从该例也不难看出GO的继承性是经过结构的嵌套来实现的
三、多态性
多态意味着一个对象有多重特征,在特定的状况下表现不一样的状态,即对应着不一样的方法
Mp3和Iphone都实现了USB接口,并分别实现接口USB定义的方法,当面向对象如此调用时:
USB u1 = new Mp3();
u1.connect(); // 打印出“mp3”
USB u2 = new Iphone();
u2.connect(); // 打印出“iphone”
一样的接口(USB)对象(u1, u2),因为实现类不一样,调用相同的方法(connect()),最终的效果是不一样的,这就是多态的做用,通常用于“控制反转”。
那么Go呢?
Go能够经过Interface、struct模拟实现多态
在src下建立usb目录,在usb目录下建立usb.go文件,里面定义USB接口
// 把接口USB放在usb包中 package usb // 定义USB接口,里面只有一个Connect()方法 type USB interface { Connect() } |
在usb目录下建立mp3.go文件,里面定义Mp3结构体,并为该结构体增长Connect(),这样就至关于实现了接口USB
// 把Mp3结构体放在usb包中 package usb import ( "fmt" ) // 定义Mp3空结构体 type Mp3 struct { } // 为Mp3增长Connect()方法,这样就缺省实现了USB接口 func (m Mp3) Connect() { fmt.Println("mp3") } |
一样,在usb目录下建立iphone.go文件,里面定义Iphone结构体
// 把Iphone结构体放在usb包中 package usb import ( "fmt" ) // 定义Iphone空结构体 type Iphone struct { } // 为Iphone增长Connect()方法,这样就缺省实现了USB接口 func (i Iphone) Connect() { fmt.Println("iphone") } |
下面演示GO语言的多态性:
在src目录下建立main.go文件,该文件与usb目录同级,里面写测试代码
package main import ( "usb" ) func main() { var m usb.USB = usb.Mp3{} m.Connect() var n usb.USB = usb.Iphone{} n.Connect() } |
执行程序,运行结果以下:
【备注】:
关于本文的演示代码能够在本章节源代码处下载