Go语言笔记-OOP面向对象

  • 面向对象的操作使用编程语言实现就是叫做面向对象编程Object-Oriented Programming

在编程语言中一般使用class来实现面向对象,但并不是说没有class就不能或者不是面向对象
Go中使用结构体struct来代替类class对对象的描述

  • 可以实现OOP的编程语言叫做面向对象语言
  • 实现面向对象这一过程叫做面向对象过程

语法层面上讲就是将一组相关的数据变量(属性)和操作函数,整合到一个对象。


package main

import "fmt"

//Go中没有class,一般使用struct代替实现oop

//对象的声明 定义就是类
type Computer struct {	//OOP对象的声明
	name string
	price int
	module []string
}

//this *value这里是使用了一个接收器和对象进行关联
//*的目的是为了指明这是一个Computer类型的指针,后面的实例化使用&也是为了取其内存地址
//因为在OOP中,推荐使用指针的引用类型来进行传递,否则默认将会是值传递。就不满足面向对象的思想了
func (this *Computer)GetComType(a bool)string{	//OOP对象的方法
	if a {
		return this.name+ "--台式机"
	} else {
		return this.name+ "--便携机"
	}
}
//函数和方法是一个东西,只不过带有接收器的函数一般被叫做方法,一般用来处理oop中的对象,由对象调用

func New(n string, p int, m []string)(*Computer, error){
	//可以实例化对象,并返回的叫做构造函数
	//一般构造函数内用来完成初始化操作和实例化对象
	obj := new(Computer)
	obj.name = n
	obj.price = p
	obj.module = m
	return obj, nil
}

func main() {
	//实例化
	//:= &Computer这种带有字面量语法的实例方式必须赋其值,不常用。
	PC1 := &Computer{	//OOP对象的实例化
		name:   "surface pro3",
		price:  2999,
		module: []string{"CPU", "RAM", "ROM"},
	}

	//常用的都是使用new来实例化对象
	PC2 := new(Computer)	//实例化初始,默认所有值都为零值
	PC2.name = "Mac book pro"
	PC2.price = 4999

	//也可以使用函数来实例化,用来实例化的函数叫做构造函数,他没有特殊的语法,就是一种普通函数
	PC3, err := New("Web-server", 15000, []string{"CPU", "ROM", "RAM"})
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("PC3 name:%v \n%v\n", PC3.GetComType(true), PC3)
	}

	fmt.Printf("PC1 name:%v \n", PC1.GetComType(false))
	fmt.Printf("PC1 price:%v \n", PC1.price)
	//成员的访问,属性和方法
	fmt.Printf("PC2 name:%v \n", PC2.GetComType(false))
	fmt.Printf("PC2 price:%v \n", PC2.price)
}

输出:

PC3 name:Web-server--台式机 
&{Web-server 15000 [CPU ROM RAM]}
PC1 name:surface pro3--便携机 
PC1 price:2999 
PC2 name:Mac book pro--便携机 
PC2 price:4999 

Process finished with exit code 0

指针传递

分别试验:构造函数是否使用指针和对象方法是否使用指针

代码:

package main

import "fmt"

//对于指针引用类型和值拷贝类型的练习

type article struct {
	name string
	price int
}
//对象的定义

func (a *article)zz(n string)string{
	return a.name+ "---"+ n
}
//对象的方法

func (a article)zz1(n string)string{
	return a.name+ "---"+ n
}
//如果不使用指针引用类型


func New(n string, p int)(*article, error){
	obj := new(article)
	obj.name = n
	obj.price = p
	return obj, nil
}
//对象实例化

func New1(n string, p int)(article, error){
	var obj article		//new返回的是一个指针类型,这里使用var初始化
	obj.name = n
	obj.price = p
	return obj, nil
}
//不使用指针引用类型

func main() {
	wp1, err := New("水杯", 10)
	if err != nil {panic(err)}
	fmt.Printf("物品:%v\n%v\n", wp1.zz("china"), wp1)
	//标准流程(都使用引用类型)

	wp2, err := New1("铅笔", 1)
	if err != nil {panic(err)}
	fmt.Printf("物品:%v\n%v\n", wp2.zz("china"), wp2)
	//实例化不使用引用类型

	wp3, err := New1("电池", 4)
	if err != nil {panic(err)}
	fmt.Printf("物品:%v\n%v\n", wp3.zz1("china"), wp3)
	//对象方法和实例化都不使用引用类型

	wp4, err := New("本子", 2)
	if err != nil {panic(err)}
	fmt.Printf("物品:%v\n%v\n", wp4.zz1("china"), wp4)
	//对象方法不使用引用类型
}

输出:

物品:水杯---china
&{水杯 10}
物品:铅笔---china
{铅笔 1}
物品:电池---china
{电池 4}
物品:本子---china
&{本子 2}

Process finished with exit code 0

结果如下表:

仅进行一次流程初始化

指针试验构造函数*构造函数
对象方法*实例化的对象值可以同步实例化的对象值正常输出,但是构建函数返回的是值拷贝
对象方法也是正常输出,但是方法返回的是值拷贝的数据,会增加内存占用实例化的值和方法返回的内容都正常,不过都是值拷贝。

结论:
在第一次初始化操作时,是否使用指针传递并不会产生不一样的输出结果。但是因为是值拷贝 ,值传递相对来说会多占用内存空间。

继承与重写

package main

import "fmt"

//OOP 继承,用go的实现方式是结构体嵌套

type headset struct {
	name string
	price int
}
//对象的定义

type wireless struct {
	headset
	//嵌套了ej的对象属性
	yc int
}
//典型的嵌套方法

type wired struct {
	ej headset
	//增加了一个headset类型的ej成员变量
	jk string
}
//另一种嵌套方法

func (a *headset)manufacturer(n string)string{
	return a.name + "---" + n
}
//对象的方法

//继承-重写
type headphones struct {
	headset
	price string
	//如果出现和父结构体成员变量相同时,优先会输出子值。这个过程叫做重写 见:54行
	jz int
}
//同样如果父结构体中有关联的对象方法,和子类冲突时,会优先使用子类的方法。这个过程也是重写 见:57行
func (a *headphones)manufacturer(n string)string{
	return a.name + "制造商:"+ n
}

type lyyx struct {
	headset
	wireless
	//这种使用俩个结构体以上的嵌套叫做 多嵌套
	yl int
}
//但是多嵌套如果要重写也是遵循子类最优先,但是!如果想多重写,不允许出现在headset和wireless类中都有个相同的成员变量,编译器将会报错。

type A struct {

}
type B struct {
	A
}
type C struct {
	B
}
//这种像链式的嵌套称为嵌套链,嵌套链的多重写,允许不同层级的成员变量名相同,最终以子类优先。
//链式嵌套可以和多嵌套同时出现,也是遵循相应规则。
//嵌套链不允许产生循环结构 比如 C嵌套B,B嵌套A,A最后嵌套C,这种编译器也会报错!

func main() {
	//实例化
	akg := new(wired)
	hw := new(wireless)
	//当使用字面量语法实例化嵌套的结构体时,如果要实例化嵌套内的成员变量必须使用下面这种方式。
	xm := &wireless{
		headset: headset{"小米", 998},
		yc:      250,
	}
	sx := new(headphones)
	sx.price = "390"
	fmt.Printf("%v %T", sx.price, sx.price)	//重写后会输出子类中的price
	fmt.Println(sx.manufacturer("shenzhen"))

	fmt.Println(xm)

	fmt.Println(hw.price)
	//访问对象继承属性的典型方式,和下面那种方法没什么本质区别 只是go提供的一种语法糖
	fmt.Println(akg.ej.price)
	//标准访问继承对象属性的方式,但是如果是使用在子结构体中新加一个父结构体类型的成员变量,就必须使用这种方式访问,上面那种语法糖就不支持了。
}

输出:

390 string制造商:shenzhen
&{{小米 998} 250}
0
0

Process finished with exit code 0
# Go 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×