神刀安全网

Go的接口与Go面向对象编程

面向对象程序设计 英语: Object-oriented programming 缩写 OOP )是种具有 对象 概念的 程序编程范型 ,同时也是一种程序开发的方法。它可能包含 数据 、属性、 代码方法 。对象则指的是 的实例。它将 对象 作为 程序 的基本单元,将程序和 数据 封装 其中,以提高软件的重用性、灵活性和扩展性 [1] ,对象里的程序可以访问及经常修改对象相关连的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象 [2] [3] 。Go语言也是一种面向对象编程的语言,但是和传统的编程语言有一些不同。但是Go也有很多传统OOP语言的特点:

  • Methods on any defined type
  • Polymorphism
  • Namespacing
  • Message Passing/Delegation

Go在定义2个对象的关系的方式上,说实话有点标新立异。

不同与传统的OOP语言的是,Go不支持Objects 和Classes,你可能会问,“如果Go不支持(Objects)对象那么如何进行面向对象编程呢?”。虽然Go没有明确的对象类型,但是Go有typs和methods来替代Objects 和Classes。Go提供的 结构体 就是把 使用各种数据类型定义不同变量组合起来高级数据类型。然后我们可以为这些数据类型声明方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。这看起来和传统的OOP语言的习惯差不多。然而Go却是不支持继承的。在Go中也没有继承类型。Go通过组合复用方式来实现继承。

组合复用

很多流行的编程语言都支持继承,继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。比如C++中的继承:

class Vehicle {   public:      void drive() {}      int getWheels() { return wheels }   private:      int wheels; };  class Car: public Vehicle {   public:      void drive() { /*Override with some behvaior */}      void honk() { /* Some honking Logic */ } };
class Vehicle {   public:     void drive() {}     int getWheels() { return wheels }   private:     int wheels; };   class Car: public Vehicle {   public:     void drive() { /*Override with some behvaior */}     void honk() { /* Some honking Logic */ } }; 

上面的代码中“Vehicle”类中定义了轮子和能够驾驶的方法,在子类中,“Car”类中,同样也有轮子但是重新定义了drive方法还增加了一个鸣喇叭(honk)方法。然而拥有这种模式设计的语言有些共同的缺点就是:使用起来不灵活。随着系统的复杂度增加,我们增加新的子类,孙子类,和曾孙类。我们的基类就会变得很难更改。因为在基类的中的改变就会影响到后代。可能会对整个系统造成不可预料的后果。

组合是一个很好的解决方案,对象的组合可以允许简单的对象组合成更大,更复杂的重用行为。在Go语言中你可以你可以嵌套各种类型来扩展他们的行为:

type Person struct {  Name string  JobTitle string  ShoeSize float32 } func (p Person) SayHello() {  fmt.Println(“Hello, I’m “, p.Name) } func (p Person) GetJobTitle() {  fmt.Println(“I’m a “, p.JobTitle) } type Doctor struct {  Person  Degree string } func (d Doctor) SayHello() {  fmt.Println(“Hello, I’m Dr.”, d.Name, “, “, d.Degree) } func (d Doctor) Diagnose() {  fmt.Println(“It’s Lupus.”) }
type Person struct {  Namestring  JobTitlestring  ShoeSizefloat32 } func (p Person) SayHello() {  fmt.Println(“Hello, I’m “, p.Name) } func (p Person) GetJobTitle() {  fmt.Println(“I’m a “, p.JobTitle) } type Doctor struct {  Person  Degreestring } func (d Doctor) SayHello() {  fmt.Println(“Hello, I’m Dr.”, d.Name, “, “, d.Degree) } func (d Doctor) Diagnose() {  fmt.Println(“It’s Lupus.”) } 

在上面的代码中我们实现我们之前c++代码的示例的功能。首先我们创建了一个“Person”的基础类型,然后我们创建了一个“Doctor”的的类型,并且将“Person”嵌入其中。这样“Doctor”就会拥有了“Person”所有特性。这种方法比传统的继承更灵活。因为每个对象松散耦合,改变一个类型并不会引起其它行为的变化。本质上通过接口的组合复用能满足面向对象所有的需求,而且不需要复杂的继承限制。

什么是接口?

但是 Go 语言里有非常灵活的 接口 概念,通过它可以实现很多面向对象的特性。接口提供了一种方式来 说明 对象的行为:如果谁能搞定这件事,它就可以用在这儿。

接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。接口里也不能包含变量。

通过如下格式定义接口:

type Namer interface {     Method1(param_list) return_type     Method2(param_list) return_type     ... }
type Namer interface {     Method1(param_list) return_type     Method2(param_list) return_type     ... } 

接口实现多态性

Go的通过接口能够方便的实现多态性,我们可以看一个简单的示例:

package main import “fmt” type Animal interface {  Type() string  Swim() string  IsFurry() bool } type Dog struct {  Name string  Breed string } type Frog struct {  Name string  Color string } func main() {  f := new(Frog)  d := new(Dog)  zoo := […]Animal{f, d}  for _, a := range zoo {  fmt.Println(a.Type(), “ can “, a.Swim())  } } func (f *Frog) Type() string {  return “Frog” } func (f *Frog) Swim() string {  return “Kick” } func (d *Dog) Swim() string {  return “Paddle” } func (d *Dog) Type() string {  return “Doggie” }
package main import “fmt” type Animal interface {  Type() string  Swim() string  IsFurry() bool } type Dog struct {  Namestring  Breedstring } type Frog struct {  Namestring  Colorstring } funcmain() {  f := new(Frog)  d := new(Dog)  zoo := […]Animal{f, d}  for _, a := range zoo {  fmt.Println(a.Type(), “ can “, a.Swim())  } } func (f *Frog) Type() string {  return “Frog” } func (f *Frog) Swim() string {  return “Kick” } func (d *Dog) Swim() string {  return “Paddle” } func (d *Dog) Type() string {  return “Doggie” } 

上面的代码看起来有一点做,那我们来看一个比较有实际意义的Go排序( Sort )功能的例子。这是一个基础包,然而开发者通过定义排序的类型实现在sort 包中“ Interface ”的接口,这个接口仅仅包含3个方法:“Len”, “Less”, and “Swap”.通过一个快速排序来调用这三个方法:

type Person struct {  Name string  Age int  ShoeSize float32 } type PeopleByShoeSize []Person func (p PeopleByShoeSize) Len() int {  return len(p) } func (p PeopleByShoeSize) Swap(i, j int) {  p[i], p[j] = p[j], p[i] } func (p PeopleByShoeSize) Less(i, j int) bool {  return (p[i].ShoeSize < p[j].ShoeSize) }
type Person struct {  Namestring  Ageint  ShoeSizefloat32 } typePeopleByShoeSize []Person func (p PeopleByShoeSize) Len() int {  return len(p) } func (p PeopleByShoeSize) Swap(i, j int) {  p[i], p[j] = p[j], p[i] } func (p PeopleByShoeSize) Less(i, j int) bool {  return (p[i].ShoeSize < p[j].ShoeSize) } 

你可以看到一个“Person”的struct和一个叫“PeopleByShoeSize”的slice。我们实现了“Interface”的接口,我们看上面的“Less”方法,在方法中我们定义了我们排序的逻辑:

func main() { people := []Person{ { Name: “Person1”, Age: 25, ShoeSize: 8, }, { Name: “Person2”, Age: 21, ShoeSize: 4, }, { Name: “Person3”, Age: 15, ShoeSize: 9, }, { Name: “Person4”, Age: 45, ShoeSize: 15, }, { Name: “Person5”, Age: 25, ShoeSize: 8.5, }, } fmt.Println(people) sort.Sort(PeopleByShoeSize(people)) fmt.Println(people) } / OUTPUT [{Person1 25 8} {Person2 21 4} {Person3 45 15} {Person4 25 8.5}] [{Person2 21 4} {Person1 25 8} {Person4 25 8.5} {Person3 45 15}] /

funcmain() {  people := []Person{  {  Name: “Person1”,  Age: 25,  ShoeSize: 8,  },  {  Name: “Person2”,  Age: 21,  ShoeSize: 4,  },  {  Name: “Person3”,  Age: 15,  ShoeSize: 9,  },  {  Name: “Person4”,  Age: 45,  ShoeSize: 15,  },  {  Name: “Person5”,  Age: 25,  ShoeSize: 8.5,  },  }  fmt.Println(people)  sort.Sort(PeopleByShoeSize(people))  fmt.Println(people) } /* OUTPUT [{Person1 25 8} {Person2 21 4} {Person3 45 15} {Person4 25 8.5}] [{Person2 21 4} {Person1 25 8} {Person4 25 8.5} {Person3 45 15}] */ 

英文原文: https://medium.com/@gianbiondi/interfaces-in-go-59c3dc9c2d98#.5w1gw9yb0

Go的接口与Go面向对象编程

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Go的接口与Go面向对象编程

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮