14天搞定Go语言,从0到1保姆级教程的第七天,来学习Go语言面向对象编程。面向对象是一种对现实世界理解和抽象的方法。面向对象的程序设计(Object Oriented Programming),简称OOP。传统面向对象主要特点可以概括为封装、继承、多态。
学习目标
(1)能够理解面向过程与面向对象
(2)能够掌握结构体
知识讲解
Ø 面向过程与面向对象
面向对象,关注的是对象。把构成问题的事务分解成各个对象,不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
面向过程,关注的是过程,分析出解决问题的步骤,然后用函数把每一个步骤实现。
在软件领域,编程初期是面向过程编程,项目一旦庞大就变得不可控,最大的原因就是代码不可复用。例如,一个软件需要创建游戏角色,这些角色需要有自己的名称、积分、血值、装备等属性,同时需要有攻击,复活等游戏行为,对于这些游戏属性可以用程序中的数据变量表示,对于游戏行为使用函数可以解决。但是数据和函数的代码散落摆放,一旦复用完全不可控。于是软件有了面向对象的编程思想,游戏角色即被看成一个对象,这个角色封装了它应有的属性和具体的行为。
相较于面向过程,面向对象有以下优势。
l 容易起名字。不同的类中方法名字可以相同,但是函数则不同,必须使用不同的名字,光起函数名字就需要大费力气;
l 代码管理方便,易于模块化开发。对象包含方法和属性,属性用来记录数据,方法表示行为,行为和数据由对象来统一管理。写出来的代码方法与属性各归各类,逻辑清晰,利于扩展;函数也表示行为,但是与函数配合的数据却散落摆放,缺乏统一管理。
l 代码冗余量小、重用性高。通过调用各个对象中的方法和属性,代码的不同的排列组合就能适应各种不同的业务场景。
在生活中,随处可见的一种事物就是对象,如人、动植物、建筑等。这些对象都具备了属性和行为两大特征:
l 属性,如一个人,有年龄、性别、爱好、职业等属性特征;
l 行为即动态特征,比如教师有讲课行为,厨师有做菜行为。
基于这两个特征,对象实现了记录数据与通过行为操作数据的结合,于是构成了多样的世界。
在计算机世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。例如,现在面临一名厨师想要做出一盘菜的实际问题,试着以面向对象的思想来解决这一实际问题。
首先可以从这一问题中抽象出对象,这里抽象出的对象为一名厨师。然后识别这个对象的属性。对象具备的属性都是静态属性,如厨师有等级、年龄等。接着识别此对象的动态行为,即厨师的切菜、炒菜等,这些行为都是此对象基于其属性而具有的动作。识别出此对象的属性和行为后,这个对象就被定义完成了,然后根据厨师具有的特性制定做菜的具体方案以解决问题。究其本质,所有的厨师都具有以上的属性和行为,可以将这些属性和行为封装起来以描述厨师这类人。
Ø Go语言面向对象
在其他编程语言中大多使用关键字“类”来定义封装对象,表示该类的具体特征,然而Go并不是一个纯面向对象的编程语言。在Go语言中的面向对象,采用更灵活的结构体替代了“类”。
Go语言并没有提供类(class),但是它提供了结构体(struct),方法(method),可以在结构体上添加。提供了捆绑数据和方法的行为,这些数据和方法与类类似。
Go语言设计的非常简洁优雅,Go没有沿袭传统面向对象编程中的诸多概念,比如继承、虚方法、构造方法和析构方法等。
虽然Go语言没有继承和多态。但是Go语言可以通过匿名字段实现继承,通过接口实现多态。在Go语言中学习面向对象,主要学习结构体(struct)、方法(method)、接口(interface)。
Ø 定义结构体与实例化
单一的数据类型已经满足不了现实开发需求,于是Go语言提供了结构体来定义复杂的数据类型。 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体的定义格式,具体示例如下。
在使用结构体的过程中注意以下3点。
l 类型名:标识结构体的名称,在同一个包内不能重复。
l 结构体中属性,也叫字段,必须唯一。
l 同类型的成员属性可以写在一行。
结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正分配内存。因此必须在定义结构体并实例化后才能使用结构体;
实例化就是根据结构体定义的格式创建一份与格式一致的内存区域。结构体实例之间的内存是完全独立的。
实例化的语法如例所示。
结构体
Ø 结构体的语法糖
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。
通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。结构体和数组中都含有语法糖。
使用内置函数new()对结构体进行实例化,结构体实例化后形成指针类型的结构体。new内置函数会分配内存。第一个参数是类型,而不是值,返回的值是指向该类型新分配的零值的指针。该函数用于创建某个类型的指针。
使用方式如例所示。
Ø 结构体是值类型
结构体作为函数参数,实际将参数复制一份传递到函数中,在函数中对参数进行修改,不会影响到实际参数。证明结构体是值类型。如例所示。
Ø 结构体的深拷贝和浅拷贝
值类型是深拷贝,深拷贝就是为新的对象分配了内存。引用类型是浅拷贝,浅拷贝只是复制了对象的指针。
结构体的拷贝实例,如例所示。
Ø 结构体作为函数的参数及返回值
结构体作为函数的参数及返回值有两种形式,值传递和引用传递,接下来通过案例了解两者的区别。
Ø 匿名结构体和匿名字段
1.匿名结构体
匿名结构体就是没有名字的结构体,无需通过type关键字定义就可以直接使用。创建匿名结构体时,同时要创建对象。匿名结构体由结构体定义和键值对初始化两部分组成。语法格式示例如下。
2.结构体的匿名字段
匿名字段就是在结构体中的字段没有名字,只包含一个没有字段名的类型。这些字段被称为匿名字段。
如果字段没有名字,那么默认使用类型作为字段名,同一个类型只能写一个。结构体嵌套中采用匿名结构体字段可以模拟继承关系。
Ø 结构体嵌套
将一个结构体作为另一个结构体的属性(字段),这种结构就是结构体嵌套。
结构体嵌套可以模拟面向对象中的以下两种关系。
l 聚合关系:一个类作为另一个类的属性
l 继承关系:一个类作为另一个类的子类。子类和父类。
结构体嵌套模拟聚合关系。
继承是传统面向对象编程中三大特征之一。用于描述两个类之间的关系。一个类(子类、派生类)继承于另一个类(父类、超类)。继承既可以避免重复代码,又可以扩展类的功能。
子类可以有自己的属性和方法,也可以重写父类已有的方法。子类可以直接访问父类所有的属性和方法。
在结构体中属于匿名结构体的字段称为提升字段,它们可以被访问,匿名结构体就像是该结构体的父类。 采用匿名字段的形式就是模拟继承关系。而模拟聚合关系时一定要采用有名字的结构体作为字段。接下来通过一个示例来用结构体模拟继承关系,参见教材例7-9。
结构体嵌套时,可能拥有相同的成员名,成员重名会发生成员名字冲突。
当重名时,编译器会报错:Ambiguous reference。
PS:梳理了Go语言面向对象编程与结构体,若有不懂或者想要全部笔记的可私信交流哦~