关于go面向对象、泛型的新理解

说到面向对象,总想到的是C++,最近看go,感觉其接口设计用起来也是蛮爽的;
go的接口只需要对应的结构体实现了相应接口的方法(一样参数,一样返回值),那么go就可以实现类似C++的运行时多态:可以将一个实现了该接口的结构体实例传入函数参数中,实现多态效果,但是go的语法没有C++限制那么严格,不需要通过冒号去写继承的代码,只需要实现接口那些函数就认为实现那个接口了。
很好理解,既然都实现了那些接口的函数,那就可以认为实现了那个接口,简单直接,省去了C++的继承代码,虽然可能会稍微导致代码不可读性,但是只要有好的命名习惯,就还是很容易可以知道某个结构的函数是个对象的。

我们知道go的interface可以等于任何值,这为多态实现提供便利;
我们使用一个例子来考虑用go怎么写:
首先假设动物有吃东西这个接口,用go描述:
···
type Animal interface {
Eat(food interface{})
}
···
我们将Eat的参数使用interface,表示可以接收任何类型的参数(虽然这样也不太对,应该是食物才对,暂且这么写吧)
然后,我们考虑人和猴子两个对象,都属于动物,那他们都应该实现Animal的接口吧,同时我们给他们加上一些属性,如体重,名称吃喝拉撒什么的都要有,用go描述:

type Human struct {
  Weight int
  Name string
}

type Monkey struct {
  Weight int
  Kind string 
}

然后对应的接口实现描述:

func (this *Human) Eat(food interface{}) {
  fmt.Println("human "+ this->Name + " eat a " + food.(string))
}

func (this *Monkey) Eat(food interface{}) {
  fmt.Println("monkey eat a " + food.(string))
}

写个main函数试试

package main
import (
  "fmt"
)

func main() {
  human := &Human{Weight:100,Name:"hijiang"}
  monkey := &Human{Weight:60, Kind:"金丝猴"}
  human.Eat("apple")
  monkey.Eat("bannaner")
}

最后输出:

  • human hijiang eat a apple
  • monkey eat a bannaner

如果再进一步考虑,食物还不应该是随便一种类型,需要有限制,那么用go描述一个食物:

type Food interface {
  GetWeight() int
  GetName() string
}
//我们特意将其成员变量小写,然后实现个接口,分别获取食物的重量和名称

接下来我们实现一个具体的食物apple和bannaner吧:

type Apple struct {
  weight int
  name string
}

type Bannaner struct {
  weight int
  name string
}

func (this *Apple ) GetWeight() int {
  return this.weight
}

func (this *Apple ) GetName() string {
  return this.name
}

func (this *Bannaner) GetWeight() int {
  return this.weight
}

func (this *Bannaner) GetName() string {
  return this.name
}

接下来我们限制下Animal接口只能输入Food类型(其实,Food是接口类型的话,可以接受任何类型):

type Animal interface {
  Eat(food Food)
}

然后修改下Human和Monkey的接口:

func (this *Human) Eat(food Food) {
  fmt.Println("human "+ this->Name + " eat a " + food.GetName()+",weight="+food.Weight())
}

func (this *Monkey) Eat(food Food) {
  fmt.Println("monkey eat a " + food.GetName()+",weight="+food.Weight())
}

main:

func main() {
  human := &Human{Weight:100,Name:"hijiang"}
  monkey := &Human{Weight:60, Kind:"金丝猴"}
  apple := &Apple{weight:100,name:"苹果"}
  bannaner := &Bannaner{weight:200, name:"香蕉"}
  human.Eat(apple)
  monkey.Eat(bannaner)
}

代码编写过程发现,函数名称一样接收器不一样是会被视为重复定义的,这个暂时还没搞明白为什么要这样。
关于go的结构体类貌似是不能用来做类似这种多态编程,暂时不研究。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 写在前面 既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解... 面向对象与面向过程 面向对象和面向过程...
    grain先森阅读 513评论 0 3
  • java继承 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。 继承就是子类继...
    863cda997e42阅读 694评论 0 1
  • 什么是对象 1.对象的概念:对特定一个存在事物2.什么是面向对象:以自我为中心对待一个特定事物存在,需要自己描述出...
    joshul阅读 725评论 0 1
  • 初识面向对象 楔子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战...
    go以恒阅读 948评论 0 6
  • 一、封装 1. 面向对象的三大特性:封装(成员变量)、继承和多态 在OC语言中,使用@interface和@imp...
    波澜不惊的少年阅读 1,335评论 0 1