Golang之面向对象

一、method
        带有接收者的函数,称之为method。
        假设定义了一个struct叫长方形,现在要计算它的面积,那么按照面向过程的思路会如下实现:
        packeage main
        import "fmt"
        type Rectange struct {
            width, height float64
        }
        func area(r Rectangle) float64 {
            return r.width*r.height
        }
        func main() {
            r1 := Rectangle(12, 2)
            r2 := Rectangle(9, 4)
            fmt.Println("Area of r1 is: ", area(r1))
            fmt.Println("Area of r2 is: ", area(r2))
        }
        这段代码中,area不是Rectangle的方法,所以需要将r1,r2作为参数传入以计算面积。我们知道C语言是不能重载的,为了解决新增类型比如圆、五边形等问题则需要为此定义多个不同名的面积计算函数,比如:area_circle、area_triangle。这种方式相对于C++的重载来看不是很优雅,在Go语言中,用了类似的解决方案,即method。
        method附属在一个给定的类型上,它的语法和函数的声明语法几乎一样,只是在func后面增减了一个receiver(也就是method所依从的主体),简单点说就是struct拥有方法area。method的语法如下:
        func (r ReceiverType) funcName(parameters) (results)
        将前面例子改造如下:
        package main
        import (
            "fmt"
            "math"
        )
        type Rectangle struct {
            width, height float64
        }
        type Circle struct {
            radius float64
        }
        func (r Rectangle) area() float64 {
            return r.width*r.height
        }
        func (c Circle) area() float64 {
            return c.radius*c.radius*math.pi
        }
        func main() {
            r1 := Rectangle(12, 2)
            r2 := Rectangle(9, 4)
            c1 := Circle(10)
            c2 := Circle(25)

            fmt.Println("Area of r1 is: ", r1.area())
            fmt.Println("Area of r2 is: ", r2.area())
            fmt.Println("Area of c1 is: ", c1.area())
            fmt.Println("Area of c2 is: ", c2.area())
        }
        使用method的时候需要注意以下几点:
        (1)虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样。
        (2)method里面可以访问接收者的字段。
        (3)调用method通过访问,就像struct里面访问字段一样。
        在上面的例子中,method方法中的Receiver是以值传递,而非引用传递。实际上,Receiver还可以是指针,二者区别在于:指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。
        method其实不仅仅可以用在struct上,而且可以用在任何自定义的类型、内置类型、struct等上面。当然struct也是自定义类型中的一个特例,你还可以通过如下形式来申明自定义类型:
        type typeName typeLiteral
        具体例子如下:
        type ages int
        type money float32
        type months map[string]int
        实际上自定义类型只是为内置类型定义了一个别名而已,类似于C语言中的typedef,如上面所示用ages替代了int。
        
二、method继承
        method也可以继承,如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method,举例如下:
        package main
        import "fmt"
        type Human struct {
            name string
            age int
            phone string
        }
        type Student struct {
            Human    //匿名字段
            school string
        }
        type Employee struct {
            Human    //匿名字段
            company string
        }
        //在human上定义一个method
        func (h *Human) SayHi() {
            fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
        }
        func main() {
            mark := Student{Human{"Mark", 25, "222-222-YYY"}, "MIT"}
            sam := Employee{Human{"Sam", 45, "111-888-XXX"}, "Golang Inc"}
            mark.SayHi()
            sam.SayHi()
        }

三、method重写
        method还能重写,类似于匿名字段冲突的处理方式。
        我们可以在Emplyee上面定义一个method,重写匿名字段的方法,具体如下:
        package main
        import "fmt"
        type Human struct {
            name string
            age int
            phone string
        }
        type Student struct {
            Human    //匿名字段
            school string
        }
        type Employee struct {
            Human //匿名字段
            company string
        }
        //Human定义method
        func (h *Human) SayHi() {
            fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
        }
        //Employee的method重写Human的method
        func (e *Employee) SayHi() {
            fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name, e.company, e.phone)
        }
        func main() {
            mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
            sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
            mark.SayHi()
            sam.SayHi()
        }
        看了上面的代码是否看到了C++的影子啊,呵呵。
        通过这些内容,我们可以设计出基本的面向对象的程序,但是Go语言的面向对象非常简单,没有任何的私有、公有关键字,通过大小写来实现(大写开头的为公有,小写开头的为私有),方法也也同样适用这个原则。






        


上一篇:设计模式(二十) 观察者模式


下一篇:mysql主从复制