zoukankan      html  css  js  c++  java
  • Go 面向对象三大特性

    #### Go 中面向对象的三大特性
    上周因为有一些事情,停更了; 停更的这段时间,花了点时间做了一个小项目(https://github.com/yioMe/node_wx_alipay_personalPay)
    原项目由node.js 写的,根据文档用Go 重写了(Gin + MySQL) ;
    1. 没有了繁琐的node安装;
    2. 没有 DB 迁移;
    3. 支付成功回调优化;
    4. 性能提升;
    5. 修复了上传二维码不能识别的问题;
    不过只重写了一小部分功能,应对日常个人支付不成问题,如有需要了解的朋友,私聊一同交流学习;
    ---
    言归正传,Go 中的面向对象的特性与传统的OOP 语言不同,我们来一一学习了解;
    ###### 封装
    封装就是把抽象的字段的对字段的操作封装在一起,数据被保护在内部,程序中的其它包只能通过被授权的操作才能对
    字段操作;
    封装的好处:
    1. 隐藏实现的细节;
    2. 可以对数据进行验证,保证数据的安全合理;
    ---
    封装实现的步骤:
    1. 将结构体,字段的首字母小写,不能被导出,其它包不能使用,类似JAVA 的private ;
    2. 在结构体所在的包提供一下工厂模式的函数,首写字母大写,类似构造函数;
    3. 提供一个首字母大写的Set 方法,用于对属性的判断并赋值
    4. 提供一个首字母大写的Get 方法,用于获取属性的值;
    5. 在Go 中没有特别强调封装,所以有其它编程语言的朋友,不需要用其它的语法特性来学习Go, 每种编程语言都有各自的特点;
    package model
    
    import "fmt"
    
    type student struct {
       Name string
       age int  // 其它的包不能直接访问
       score float64 // 其它的包不能直接访问
    }
    
    // 工厂方法,相当于构造函数
    func NewStudent(name string) *student{
       return &student{
          Name:name,
       }
    }
    // 为了访问和更改结构体的属性,编写一对GetXxx/SetXxx 的方法
    // this 只是接收类型的名称, 可以命名为任意合法的标识符
    func (this *student) GetAge() int {
       return this.age
    }
    func (this *student) SetAge(age int){
       // 可以在Set 方法里对数据进行校验
       if age < 0 || age > 100 {
          fmt.Println("age is wrong")
          return
       }
       this.age = age
    }
    func (this *student) GetScore() float64{
       return this.score
    }
    func (this *student) SetScore(score float64) {
       if score < 0 || score > 100 {
          fmt.Println("score is wrong")
          return
       }
       this.score = score
    }
    

      

    
    
    package main
    
    import (
       "fmt"
       "personalPayment/model"
    )
    
    func main(){
       p := model.NewStudent("jack")
       p.SetAge(20)
       p.SetScore(200)
       fmt.Println(*p)
       fmt.Println(p.Name,"age=",p.GetAge(),"score=",p.GetScore())
    }
    

      


    ---
    ###### 继承
    1. 继承可以解决代码的复用问题
    2. 当多个结构体有相同的属性和方法时,可以从这些结构体中抽象一下基础的结构体,在该结构体中定义相同的属性和方法;
    3. Go 中实现继承是通过结构体匿名嵌套来实现;
    基本语法:
    type Person struct {
    Name string
    Age int
    }

    type Student struct {
    Person // 嵌套的结构体,实现继承
    Score float64
    }
    案例:
    package model
    
    import "fmt"
    type person struct {
       Name string
       age int
    }
    type student struct {
       person
       score float64 // 其它的包不能直接访问
    }
    type teacher struct {
       person
       class string
    }
    
    // 学生的工厂方法,相当于构造函数
    func NewStudent(name string) *student{
       return &student{ person:person{
          Name:name,
       },
       }
       }
    // 老师的工厂方法
    func NewTeacher(name string) *teacher{
       return &teacher{person:person{
          Name:name,
       }}
    }
    // 基础结构的公众方法
    func (this *person) GetAge() int {
       return this.age
    }
    func (this *person) SetAge(age int){
       // 可以在Set 方法里对数据进行校验
       if age < 0 || age > 100 {
          fmt.Println("age is wrong")
          return
       }
       this.age = age
    }
    // 学生的方法
    func (this *student) GetScore() float64{
       return this.score
    }
    func (this *student) SetScore(score float64) {
       if score < 0 || score > 100 {
          fmt.Println("score is wrong")
          return
       }
       this.score = score
    }
    // 老师的方法
    func (this *teacher) GetClass() string {
       return this.class
    }
    func (this *teacher) SetClass(class string){
       this.class = class
    }
    

      

    
    
    package main
    
    import (
       "fmt"
       "personalPayment/model"
    )
    
    func main(){
       s := model.NewStudent("jack")
       // 调用公用的结构体方法
       s.SetAge(20)
       // 调用自己的方法
       s.SetScore(100)
       fmt.Println(s.Name,s.GetAge(),s.GetScore())
       t := model.NewTeacher("tom")
       // 调用公用的结构体方法
       t.SetAge(40)
       // 调用自己的方法
       t.SetClass("English")
       fmt.Println(t.Name,t.GetAge(),t.GetClass())
    }
    

      


    继承的使用和注意事项
    1. 结构体可以使用嵌套匿名的结构体中的所有的属性和方法,不论大写与小写
    2. 结构体中匿名结构体的字段和方法可以简化;
    3. 当结构体和匿名结构体有相同的属性和方法时,编译器采用就近原则,如果需要访问匿名结构体中的字段
    和方法需要通过匿名结构体的名称来区分;
    4. 如果一个结构体嵌套了一个有名称的结构体,这种模式称为组合,在访问组合的结构体或方法时需要加上结构体的名字;
    package main
    
    import (
       "fmt"
    )
    
    type person struct {
       Name string
       Age int
       skill string
    }
    type student struct {
       person
       score float64
    }
    func (p *person) Say(){
       fmt.Println("I am a person")
    }
    func (p *person) Do(){
       fmt.Println("I am doing something")
    }
    
    type A struct {
       Name string
    }
    type B struct {
       A
       Name string
    }
    type C struct {
       Name string
    }
    type D struct {
       c C
       Age int
    }
    func main(){
       s := &student{}
       s.person.Say()
       s.person.Do()
       s.person.Name = "jack"
       s.person.Age = 20
       s.person.skill = "speak"
       fmt.Println(*s)
       // 对匿名结构体中的属性方法可以简化为
       s.Say()
       s.Do()
       s.Name = "jack2"
       s.Age = 21
       s.skill = "laugh"
       fmt.Println(*s)
       // 如果结构体和匿名结构体中有相同的属性或方法,编译器将采用就近原则,
       // 如果需要访问匿名结构体的属性和方法需要通过匿名结构体的名称
       a := B{
          A: A{
             Name:"aaa",
          },
          Name:"bbb",
       }
       fmt.Println(a.Name) // bbb
       fmt.Println(a.A.Name) // aaa
       // 对于组合,在访问继承结构体的方法或属性时需要加上结构体的名称 
       d := D{
          c:C{Name:"ccc"},
          Age:20,
       }
       fmt.Println(d.Age) // 自己的属性
       fmt.Println(d.c.Name) // 访问继承的属性
    }
    

      个人微信公众号上有最新文章,欢迎关注一同交流学习

  • 相关阅读:
    Oracle查询数据表结构/字段/类型/大小
    Oracle 如何修改列的数据类型
    数组声明和使用要点
    关于转发和重定向的路径问题!
    Java高级架构师(一)第29节:完成下订单和修改库存的功能
    Java高级架构师(一)第28节:Index、商品详细页和购物车
    Java高级架构师(一)第27节:实现index功能的开发
    《深入理解Spark-核心思想与源码分析》(三)第三章SparkContext的初始化
    《深入理解Spark-核心思想与源码分析》(二)第二章Spark设计理念和基本架构
    《深入理解Spark-核心思想与源码分析》(一)总体规划和第一章环境准备
  • 原文地址:https://www.cnblogs.com/Mail-maomao/p/11492644.html
Copyright © 2011-2022 走看看