目录
一.面向对象编程的四大特性
抽象,封装,继承,多态
抽象:把一类事物的共有的属性(字段)和行为方法)提取出来,形成一个物理模型(结构体)。这种研究问题的方法称为抽象。(可以使用结构体完成抽象)
封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
封装的实现步骤:
1)将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似private
2)给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
3)提供一个首字母大写的Set 方法(类似其它语言的public),用于对属性判断并赋值
4)提供一个首字母大写的Get方法(类似其它语言的public),用于获取属性的值
继承:面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
(1)通过继承创建的新类称为“子类”或“派生类”。
(2)被继承的类称为“基类”、“父类”或“超类”。
(3)多级(结构体)继承,即为组合
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
多态:是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态(使用接口与结构体进行实现多态)
二.代码讲解
实现抽象代码:
type Phone struct {
name string
}
type Camera struct {
name string
}
//USB接口 Phone的实现
func (p Phone) start() {
fmt.Printf("%s手机已经插入数据线,可以开始使用\n", p.name)
}
func (p Phone) stop() {
fmt.Printf("%s手机已经退出手机USB连接,暂停使用\n", p.name)
}
//USB接口 Camera的实现
func (c Camera) start() {
fmt.Printf("%s相机已经插入数据线,可以开始使用\n", c.name)
}
func (c Camera) stop() {
fmt.Printf("%s相机已经退出手机USB连接,暂停使用\n", c.name)
}
通过定义结构体,然后各定义了它们的字段,方法。从而实现了类的抽象
实现封装代码:
type Cat struct {
//将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似private
name string
age int
}
//给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
func NewCat(name string, age int) *Cat {
return &Cat{
name,
age,
}
}
//提供一个首字母大写的SetMsg 方法(类似其它语言的public),用于对属性判断并赋值
func (c *Cat) SetMsg(name string, age int) {
if age < 100 {
c.name = name
c.age = age
} else {
fmt.Println("这年龄太大了活不那么久")
}
}
//提供一个首字母大写的Getmsg 方法(类似其它语言的public),用于对属性判断并赋值
func (c *Cat) GetMsg() (string, int) {
return c.name, c.age
}
func (c *Cat) Shout() {
fmt.Printf("Hi, I am %s, aged %d, 喵喵喵\n", c.name, c.age)
}
1)将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似private
由上可看出,字段没有进行大写,所以无法被外部包访问,模拟了private
2)给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
3)提供一个首字母大写的Set 方法(类似其它语言的public),用于对属性判断并赋值
这里创建了SetMsg方法进行对未导出字段进行修改赋值,模拟了其他语言的public状 态下的字段进行引用赋值
4)提供一个首字母大写的Get方法(类似其它语言的public),用于获取属性的值
这里创建了GetMsg方法进行对未导出字段进行查看其字段值,模拟了其他语言的public状 态下的字段进行输出查看值
继承代码讲解:
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
继承:
type Phone struct {
name string
}
//ColorPhone继承了Phone的特性(所定义好的各种字段信息)。还带有了自己独特的风格(除了拥有Phone的字段信息,还有自己专属的字段信息)
type ColorPhone struct {
Phone //被继承(嵌套)的结构体
color string
}
//以下是继承的实现 (提供了三个方法 init初始化对象信息 ,start和stop)
func (p *ColorPhone) set(name, color string) {
p.name = name
p.color = color
}
func (p *ColorPhone) start() {
fmt.Printf("%s%s的手机已经连接USB,开始工作\n", p.color, p.name)
p.Phone.start()
}
func (p *ColorPhone) stop() {
fmt.Printf("%s%s的手机已经退出连接USB,停止工作\n", p.color, p.name)
p.Phone.start()
}
这里的 ColorPhone 结构体继承(嵌套)了Phone结构体,则ColorPhone具有了Phone结构体的字段以及方法,并且也具有自己的独特风格(属于自己的字段),这就实现了继承的效果
组合:
而假如多重嵌套结构体,则到了组合模式的概念。
type A struct {
Name string
score int
}
type B struct {
Name string
age int
}
type C struct {
A//嵌套的匿名结构体
B
Name string
}
type D struct {
xx C//有名结构体
xxx B
}
这里则需要注意:
1.结构体可以使用嵌套匿名结构体所有的字段和方法,即 首字母大写或者小写的字段、方法,都可以使用。
var c C
c.A.Name = "kangkang"
c.B.Name = "wangwang"
c.Name = "liming"
2.结构体嵌入两个(或多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时
结构体本身没有同名的字段和方法),在访问时,就必须明确指定匿名结构体名字,
否则编译报错,
type C2 struct {
/*
需要定义名字
A
A
*/
a1 A
a2 A
}
若两个相同的匿名结构体进行嵌套则需要进行声明名字,否则会报错
实现多态代码:
type USB interface {
start()
stop()
}
type Phone struct {
name string
}
type Camera struct {
name string
}
type Computer struct {
}
//以下是 USB接口实现多态过程(一个接口多种不同状态的实现)
//USB接口 Phone的实现
func (p Phone) start() {
fmt.Printf("%s手机已经插入数据线,可以开始使用\n", p.name)
}
func (p Phone) stop() {
fmt.Printf("%s手机已经退出手机USB连接,暂停使用\n", p.name)
}
//USB接口 Camera的实现
func (c Camera) start() {
fmt.Printf("%s相机已经插入数据线,可以开始使用\n", c.name)
}
func (c Camera) stop() {
fmt.Printf("%s相机已经退出手机USB连接,暂停使用\n", c.name)
}
//接口体现多态的两种方式: 1.多态参数 2.多态数组
//多态参数
func (computer Computer) Working(usb USB) {
usb.start()
usb.stop()
}
func main(){
//多态数组
usbArr := [...]USB{phone, camera}
for _, v := range usbArr {
computer.Working(v)
//遍历出的哪个类型,就哪个类型实现多态
}
首先我认为是可以使用接口和结构体的内容来实现Java中的多态,而接口当做是父类,结构体当做子类 当一个结构体或者多个结构体实现了接口中的所有方法时,就实现了这个接口,也就是说满足上面的 条件,子类(结构体)就继承了父类(接口), 当多个结构体都继承了父类接口时,因为各个结构体的类型不同(例如:接口定义了“叫”这个方法,而“猫”结构体,“狗”结构体等等都实现了这个方法,但他们的类型属性不同。)所以这个接口就实现了多态