Go中的面向对象

目录

1.学习内容

1.Go中的面向对象

1.概念

2.封装+值引用和引用传递

3.继承

4.练习01

5.多态和接口

6.类型断言

7.接口和继承

8.回顾

9.重难点

2.总结


1.学习内容

Go不是一个纯粹的纯面向对象语言,所以在学习中,难免会出现一些曲折,这些难以理解的问题,让我们的学习之路有点艰难,所以在学习之后,能够回过头来,在进行巩固和复习,会让我们的即使更加牢固,所以通过学习还有一些视频讲解,对Go的面向对象再次进行学习。

1.Go中的面向对象

1.概念

面向对象的四大特点:封装,继承,多态,(抽象)

封装:将业务相近的变量,函数封装为结构体(类)

化繁为简,减少直接管理的成员数,以便于做大规模的开发

继承:将公共的部分提取到父类,减少重复代码

多态:一个父类有多种不同的具体子类形态

共性:通过调用父类方法去调度子类实例

个性:不同子类对父类方法的具体实现各不相同

————

抽象:父类接口只定义方法,不做具体实现——战士接口——方法1.进攻 方法2.防守

——显卡接口——显示图形

2.封装+值引用和引用传递

package main
​
import "fmt"
​
type Person struct {
   //封装结构体的属性
   name  string
   age   int
   sex   bool
   hobby []string
}
​
/*封装结构体的方法
-无论方法的主语定义为值类型还是指针类型,对象值和对象指针能够正常访问
-通常会将主语定义为指针类型——毕竟西门的副本吃了饭,肉不会长到本人身上去
*/
​
func (p *Person) Eat() {
   fmt.Println(p.name, "爱吃米饭")
}
func (p *Person) Drink() {
   fmt.Println(p.name, "爱吃喝酒")
}
func (p *Person) Love() {
   fmt.Println(p.name, "爱小美")
}
func (p *Person) SelfIntroduce() {
   fmt.Println("I am ", p.name, "Today is ", p.age)
}
func MakeHimlove(p Person) {
   p.Love()
   //玩一次年轻一年
   p.age -= 1
}
func Makehislove(p *Person) {
   p.Love()
   //玩一次年轻一年
   p.age -= 1
}
// 这个方法传递值或指针,效果是一样的
func Add(p *Person, a, b int) (sum int) {
   fmt.Println("做加法")
   return a + b
}
func main01() {
   //创建对象,通过对象的值去访问对象的属性和方法
   //设置空白的对象(object)/实例(instance)
   per := Person{}
   //设置其属性
   per.name = "西门"
   //访问其方法
   per.Eat()
   per.Drink()
   per.Love()
}
func main02() {
   //创建对象,通过对象的值去访问对象的属性和方法
   //创建对象时,给进行赋值
   //hegePtr := &Person{
   // name: "西门狗",
   // age:  50,
   // sex:  true,
   //}
   //按照顺序给所有属性赋值
   hegePtr := Person{"西门", 5, true, []string{"打游戏"}}
   //访问其方法
   hegePtr.SelfIntroduce()
   hegePtr.Eat()
   hegePtr.Drink()
   hegePtr.Love()
   //设置空白的对象(object)/实例(instance)
   per := Person{}
   //设置其属性
   per.name = "西门"
​
}
func main() {
​
   hegePtr := Person{"西门", 10, true, []string{"打游戏"}}
   //指针是真身
   //要求传递指针就必须传递指针
   Makehislove(&hegePtr)
   //要求传递值就必须传递值
   MakeHimlove(hegePtr)
   //值传递传递的是副本,引用传递传递的才是真身
   for i := 0; i < 7; i++ {
      MakeHimlove(hegePtr)
   }
   fmt.Println(hegePtr.age)
   for i := 0; i < 7; i++ {
      Makehislove(&hegePtr)
   }
   fmt.Println(hegePtr.age)
   //通过上述实例我们可以看到,只有当指针传递的时候,才能改变当初的值
   //所以我们要改变值的时候,就是需要值传递
}

3.继承

继承的目的是为了发展,增加新的属性和方法,修改父类的属性和方法,覆写(overwrite)父类方法

package main
​
import "fmt"
​
type Person struct {
   //封装结构体的属性
   name  string
   age   int
   sex   bool
   hobby []string
}
​
/*封装结构体的方法
-无论方法的主语定义为值类型还是指针类型,对象值和对象指针能够正常访问
-通常会将主语定义为指针类型——毕竟西门的副本吃了饭,肉不会长到本人身上去
*/
​
func (p *Person) Eat() {
   fmt.Println(p.name, "爱吃米饭")
}
func (p *Person) Drink() {
   fmt.Println(p.name, "爱吃喝酒")
}
func (p *Person) Love() {
   fmt.Println(p.name, "爱小美")
}
func (p *Person) SelfIntroduce() {
   fmt.Println("I am ", p.name, "Today is ", p.age)
}
​
// coder特有的方法
// 写代码的
type coder struct {
   //持有一个父类声明
   Person
   //会的语言
   langs []string
}
​
func (c *coder) Code() {
   fmt.Println(c.name, "正在写代码")
}
​
type driver struct {
   //持有一个父类声明
   Person
   //司机id
   dId int
   //是不是正在开车
   idDriving bool
}
​
func (p *driver) Drink() {
   if !p.idDriving {
      fmt.Println(p.name, "爱喝酒")
   } else {
      fmt.Println("正在开车,不能喝酒")
   }
​
}
func main() {
   fPtr := new(driver)
   //访问父类的属性和方法
   fPtr.name = "嫖哥"
   fPtr.idDriving = true
   fPtr.Drink()
}
func main04() {
   c := new(coder)
   c.name = "阿门西"
   c.Code()
   c.langs = []string{"中文", "go"}
   c.Drink()
}

4.练习01

package main
​
import "fmt"
​
// 学生结构体
type Student struct {
   Reader
​
   //学生特有属性
   Name  string
   Major string
}
​
func (s *Student) Study() {
   fmt.Println(s.Name, "正在学习", s.Major)
​
}
​
// 老师结构体
type Teacher struct {
   Reader
​
   //老师特有属性
   Course string
   Name   string
}
​
func (t *Teacher) Teach() {
   fmt.Println(t.Name, "正在教学", t.Course)
​
}
​
// 覆写交罚金,老师不用交
func (t *Teacher) PayPenalty(money float64) {
   //r.Balance -= money
   fmt.Println("老师不用交罚金")
}
​
type Book struct {
   //书籍id
   BookId string
   //书的名字
   Name string
   //书的价格
   Price float64
   //书的作者
   Author string
}
type Reader struct {
   //读者id
   ReaderId string
   //读者余额
   Balance float64
}
​
func (r *Reader) BorrowBook(b *Book) {
   fmt.Println(r.ReaderId, "借阅了", b.BookId)
}
func (r *Reader) ReturnBook(b *Book) {
   fmt.Println(r.ReaderId, "归还了", b.BookId)
}
func (r *Reader) PayPenalty(money float64) {
   r.Balance -= money
   fmt.Println(r.ReaderId, "缴纳罚金", money, "剩余余额", r.Balance)
}
​
func main() {
   b1 := Book{Name: "水浒传",
      Author: "小生",
      Price:  20.1,
      BookId: "123",
   }
   b2 := Book{"三国", "小理", 57.1, "1234"}
   b3 := new(Book)
   b3.Author = "红楼"
   b3.Name = "珊莎"
   b3.Price = 100
   b3.BookId = "0122"
   fmt.Println(b1, b2, b3)
   //创建学生和老师
   Stu1 := Student{Reader{"001", 100}, "狗剩", "英语"}
   r1 := Reader{"002", 200}
   s2 := Student{r1, "丽丽", "go"}
   fmt.Println(Stu1, r1, s2)
   Ter01 := Teacher{r1, "老王", "chinese"}
   fmt.Println(Ter01)
   //实现方法
   //在这里注意new的和直接赋值的区别
   s2.BorrowBook(&b1)
   Ter01.Teach()
   Stu1.BorrowBook(b3)
​
}

5.多态和接口

package main
​
//接口只有方法的定义,没有实现全部是抽象方法
//实现接口:结构体实现接口的全部抽象方法,就成为结构体实现方法
//多态:一个父类/接口有不同的子类实现,这个例子中有程序员等
//共性:都会劳动休息
//个性:劳动和休息方式各不相同
import (
   "fmt"
   "math/rand"
   "time"
)
​
type Worker interface {
   //每天工作几小时
   Work(hour int) (product string)
   //休息
   Rest()
}
​
// 定义结构体
type Coder struct {
   skill string
}
​
func (c *Coder) Work(hour int) (product string) {
   fmt.Println(hour)
   fmt.Println(c.skill)
   return "BUG"
}
func (c *Coder) Rest() {
   fmt.Println("你他妈休息啥")
}
​
// 码农特有的方法
func (c *Coder) Workhome() {
   fmt.Println("在家工作")
}
​
type Product struct {
   skill string
}
​
func (p *Product) Work(hour int) (product string) {
   fmt.Println(hour)
   fmt.Println(p.skill)
   return "无逻辑需求"
}
func (p *Product) Rest() {
   fmt.Println("你他妈休息啥")
}
​
type Boss struct {
   skill string
}
​
func (b *Boss) Work(hour int) (product string) {
   fmt.Println(hour)
   fmt.Println(b.skill)
   return "无逻辑需求"
}
func (b *Boss) Rest() {
   fmt.Println("你他妈休息啥")
}
​
func main() {
   workers := make([]Worker, 0)
   workers = append(workers, &Coder{"写代码"})
   workers = append(workers, &Product{"拍脑袋"})
   workers = append(workers, &Boss{"吹牛比"})
   r := rand.New(rand.NewSource(time.Now().UnixNano()))
   weeker := r.Intn(7)
   fmt.Println(weeker)
   if weeker > 0 && weeker < 6 {
      //全体工作
      for _, worker := range workers {
         //调度共性,无视具体类型
         worker.Work(8)
      }
   } else {
      //全体休息
      for _, worker := range workers {
         //对接口实例做类型断言(类型判断)
         //判断当前worker是否是Coder指针
         if coder, ok := worker.(*Coder); ok {
            coder.Rest()
            coder.Work(8)
         } else {
            fmt.Println(coder.skill)
         }
      }
   }
}

6.类型断言

package main
​
import "fmt"
​
// 类型断言
// 判断一个接口的实例
func TyoeJudge(items ...interface{}) {
   for i, x := range items {
      switch x.(type) { //这里进行判断这个是哪一个类型,判断之后我们进行输出
      case bool:
         fmt.Printf("第%d个参数是bool类型,值是%v\n", i, x)
      case float32:
         fmt.Printf("第%d个参数是float32类型,值是%v\n", i, x)
      case float64:
         fmt.Printf("第%d个参数是float64类型,值是%v\n", i, x)
      case int, int32, int64:
         fmt.Printf("第%d个参数是int类型,值是%v\n", i, x)
      case string:
         fmt.Printf("第%d个参数是string类型,值是%v\n", i, x)
      case Student01:
         fmt.Printf("第%d个参数是Student01类型,值是%v\n", i, x)
      case *Student01:
         fmt.Printf("第%d个参数是*Student01类型,值是%v\n", i, x)
      default:
         fmt.Println("类型不确定")
      }
   }
}
​
type Student01 struct {
}
​
// // 在类型断言的时候,我们还可以进行特定的类型断言
//
// if coder,ok := xxx.(*Coder):ok{
//    //确定是程序猿
//    //此时是指针类型
// } else{
//
//    //判断不是
// }
func main() {
   var n1 float64 = 1.2
   var n2 float32 = 3.1
   var n3 int = 34
   var n4 string = "123"
   stu1 := Student01{}
   stu2 := &Student01{}
   TyoeJudge(n1, n2, n3, n4, stu2, stu1)
}

7.接口和继承

这里就主要写了两者关系,后面没有实现接口的具体方法,主要讲解的是有显示和隐式两种继承方法,当一个结构体的指针实现了一个接口,就可以赋值给一个接口,就是实现了这个的接口,如果没有实现其中的一个方法的话,那就是没有实现

// 的定义两个父类接口
// 定义人接口
type People interface {
   Eat(foot string) (name string)
   Die()
}
​
// 定义战士
type Fighter interface {
   Attack() (booldloss int)
   Defind()
}
​
// 显示的继承父类接口
type Beast interface {
   People
   Fighter
   Run()
}
​
// 隐式继承父类接口
type Beast01 interface {
   People
    //隐式继承接口,没有明确的说继承,但是事实上定义了其全部抽象的方法
   Attack() (booldloss int)
   Defind()
   //特有方法
   Run()
}

8.回顾

9.重难点

  1. 在调用方法的时候,使用值和值都可以调用——建议是,尽量使用指针,能最大程度的避免对本来的修改影响不到真身

  2. 作主语时,使用 值或指针效果一致,但做参数时,一个是拷贝式值类型,一个是地址引用类型

  3. 无论使用值还是指针做主语,去访问属性和方法,其功能是一致的:

    p := &Person{age: 10}
    p.Love()
  4. 定义方法是,方法的主语尽量使用指针,一方面是模仿SDK,一方面是最大程度减少值传递的拷贝效应的负面影响

  5. 对象做参数,值传递是拷贝的:指针传递(引用传递/地址传递)才是传递真身

  6. 在OOP的世界里,值能够做的指针都能做,反过来就是不成立的

  7. 创建对象的方式:

    1. 创建空白对象:p := Person{}

    2. 创建对象时,有选择的给指定属性赋值:p :=Person(Age:20,Name:"张三“)

    3. 创建对象时,完整有序的给所有属性赋值:p :=Person(20,"张三“)

    4. 通过内建函数创建对象指针: pPter := new(Person):new的参数

  8. new(Type)*Type用于创建结构体的实例指针,参数是结构体的名字,返回的是{所有属性都为默认值的对象}的指针

  9. 名字的命名可以深度的望文生义,

  10. 类型名称大写开头,外部包可以创建它的对象,反之亦然,

  11. 属性名和方法名大写开头,外部包就可以通过实例(或指针)进行访问,反之亦然

  12. 对接口的实现,语法上要严格区分到底是实例实现了接口还是指针实现了接口,推荐指针

  13. 对接口进行类型断言,只能断言为实例或指针中的一种,具体取决于【到底是实例还是指针】

  14. Woeker,workers := make([]Worker, 0),是接口能把实例a丢入一个切片,意味着a必须是实现了这个接口的子类实例或指针,

  15. 只要a是该接口的实例,就可以进行append,也可以var worker = a,进行赋值

  16. 接口实例只认指针!不管实现接口方法的主语是指针还是值!断言也只能断言为指针!

2.总结

面向对象是重要的一部分,在日后的学习之中,肯定是有重要帮助的,所以我们需要进行学习,并且是重点学习,这可以让我们的基础更加牢靠,所以,当一段时间之后,就要复习,与便于让啊我们对这个理解加深,使得我们学习有更好的成效。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值