12 面向对象

[TOC]

面向对象 OOP

面向对象三大特性

  • 封装、继承、多态

Go面向对象编程特性

  • Go没有class类,Go使用struct替代了类的作用。

  • Go支持面向对象编程(OOP),但是和传统的面向对象有区别,并不是纯粹的面向对象语言,因此Go定义为支持面向对象编程是比较准确的。

  • Go没有类,Go的结构体和面向对象语言的class有同等地位,Go通过struct来实现OOP特性。

  • Go面向对象编程非常简洁,去掉了传统OOP语言的继承、方法重载、构造函数、析构函数、隐藏的this指针等等。

  • Go有面向对象编程的继承、封装和多态的特性,只是实现的方式和其它OOP语言不一样,如继承,Go没有extends关键字,继承是通过匿名字段来实现。

  • Go的OOP很优雅,OOP本身就是语言类型系统的一部分,通过接口Interface关联,耦合性低,非常灵活,因此Go是面向接口编程,面向接口编程是它非常重要的特性。

封装

工厂模式

  • Go中没有构造函数,通过工厂模式替代构造函数功能。当结构体定义为私有,但是别的包又需要用到它,就可以使用工厂模式实现。

  • 私有结构体实例化:写一个可以生成私有结构体实例并将实例返回的公有函数,外界通过调用函数获得实例。

  • 私有字段访问:为结构体绑定可操作私有字段的方法,如GET方法读取私有字段,SET方法修改私有字段。

封装

  • 将一类事物共有的属性和行为提取出(抽象),形成一个模板(struct)。

  • 将字段和对字段的操作封装在一起,数据保护在内部,其它包只能通过暴露的方法操作字段。

  • 隐藏实现细节,对数据进行验证,保证数据安全。

go实现封装的方式

  • 将结构体和它的字段首字母小写,以达到私有的目的。

  • 为结构体提供一个工厂模式的公开函数,用于外界获取结构体实例,类似于构造函数。

  • 为需要暴露的结构体字段绑定一套Get、Set方法,Get方法可以获取字段数据,Set方法修改字段数据,Set方法中可以对数据合理性进行判断。

  • go不强调封装,go本身对面向对象的特性做了简化,因为go认为程序作者有义务保证数据合理性。

继承(组合)

Go没有继承的语义,结构和字段之间是“has a”的关系,而不是“is a”的关系。没有父子的概念,仅仅是整体和局部的概念,所以一般称这种嵌套的结构体和字段的关系为组合。

组合的优点

  • 代码冗余减少,有利于维护、功能扩展。

go使用嵌套匿名结构体的方式实现组合

  • 结构体嵌套匿名结构体所有的字段和方法都可使用,包括私有的。

  • 嵌套匿名结构体继承中,编辑器采用就近访问原则,实例本身拥有的字段优先于匿名结构体中的字段。

  • 嵌套匿名结构体和结构体本身有一样的字段的时候,其实是两个字段都存在,一个叫b.Name,另一个是b.A.Name

  • 可以通过匿名结构体名称来访问匿名结构体本身的变量,如b.A.Name,它和b.Name是完全独立的两个变量

  • 嵌入多个结构体,它们之间有相同字段,在宿主没有它的字段的情况下,必须指定是哪个结构体的才能正确访问。

嵌套匿名结构体实例化

  • 嵌套匿名结构体实例化也可以直接指定各个匿名结构体的字段的值

多重组合

  • 嵌套多个匿名结构体

  • 该结构体可以直接访问嵌套的结构体的字段和方法,从而实现多重组合

  • !为了保证代码间接性,一般不使用多重组合

嵌入基本数据类型

  • 结构体也可以匿名嵌入基本数据类型

  • type A struct {int} //匿名嵌入int,使用时a.int = 9999的方式使用

组合关系

  • 有名结构体嵌入称为组合关系,访问有名结构体字段必须带上结构体名

组合方法集

方法集调用,直接通过类型实例调用方法时Go编译器会进行自动转换(实例或指针转换为方法绑定的指针或实例)。

  • Go函数的调用实参都是值拷贝,方法调用参数传递也是一样的机制,具体类型变量传递给接口时也是值拷贝,如果传递给接口变量的值类型,但调用方法的接受者是指针类型,则程序运行时虽然能够将接受者转换为指针,但这个指针是指针的副本,并不是原变量的指针。Go在编译时做了严格的方法集合的检查,不允许产生这种调用,如果传递给接口的变量是指针类型则接口调用的是值类型的方法,程序运行时能够自动转换为值类型。

多态

实例具有多种形态即为多态。

  • 在Go中多态特征是通过接口实现的,可以按照统一的接口来调用不同的实现,这时接口变量就呈现不同的形态。

类型断言 assert

  • 判断实例是否是指向一个类型的变量。

  • 目标类型变量 = 实例.(目标类型)

  • 带检测的类型断言,即使类型不匹配也不会报panic

  • 目标类型变量,成功与否 := 实例.(目标类型)

多态与类型断言应用

  • 猫和狗都实现了动物接口,共有sleep()方法,而有一个work(a animal)函数,猫和狗的实例都可调用,只需要1个函数形参为animl接口,这样猫和狗都可以使用这个函数,在函数中通过类型断言来确定猫和狗的不同工作。

Last updated