zoukankan      html  css  js  c++  java
  • Go 面向对象编程

    Go 并不是完全面向对象的编程语言。Go 官网的 FAQ 回答了 Go 是否是面向对象语言,摘录如下。

    可以说是,也可以说不是。虽然 Go 有类型和方法,支持面向对象的编程风格,但却没有类型的层次结构。Go 中的“接口”概念提供了一种不同的方法,我们认为它易于使用,也更为普遍。Go 也可以将结构体嵌套使用,这与子类化(Subclassing)类似,但并不完全相同。此外,Go 提供的特性比 C++ 或 Java 更为通用:子类可以由任何类型的数据来定义,甚至是内建类型(如简单的“未装箱的”整型)。这在结构体(类)中没有受到限制。

    结构体替代类

    Go 不支持类,而是提供了结构体。结构体中可以添加属性和方法。这样可以将数据和操作数据的方法绑定在一起,实现与类相似的效果。

    文件结构:

    workspacepath -> oop -> employee -> employee.go  

    workspacepath -> oop -> main.go

    //employee.go文件
    package employee import ( "fmt" ) type Employee struct { FirstName string LastName string TotalLeaves int LeavesTaken int } func (e Employee) LeavesRemaining() { fmt.Printf("%s %s has %d leaves remaining", e.FirstName, e.LastName, (e.TotalLeaves - e.LeavesTaken)) }
    //main.go文件
    package main import "oop/employee" func main() { e := employee.Employee { FirstName: "Sam", LastName: "Adolf", TotalLeaves: 30, LeavesTaken: 20, } e.LeavesRemaining() }

    1.Go 并不支持构造器。如果某类型的零值不可用,需要程序员来隐藏该类型,避免从其他包直接访问。程序员应该提供一种名为 NewT(parameters) 的 函数,按照要求来初始化 T 类型的变量。  

    2.应该让 Employee 结构体不可引用,修改 Employee为employee,这样别的文件就不能引用。

    //employee.go文件
    package employee import ( "fmt" ) type employee struct { firstName string lastName string totalLeaves int leavesTaken int } func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee { e := employee {firstName, lastName, totalLeave, leavesTaken} return e } func (e employee) LeavesRemaining() { fmt.Printf("%s %s has %d leaves remaining", e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken)) }
    //main.go文件
    package main import "oop/employee" func main() { e := employee.New("Sam", "Adolf", 30, 20) e.LeavesRemaining() }  

    总结:Go 不支持类,但结构体能够很好地取代类,而以 New(parameters) 签名的方法可以替代构造器。

    组合取代继承

    Go 不支持继承,但它支持组合(Composition)。组合一般定义为“合并在一起”。汽车就是一个关于组合的例子:一辆汽车由车轮、引擎和其他各种部件组合在一起。

    在 Go 中,通过在结构体内嵌套结构体,可以实现组合。

    组合的典型例子就是博客帖子。每一个博客的帖子都有标题、内容和作者信息。使用组合可以很好地表示它们。通过学习本教程后面的内容,我们会知道如何实现组合。

    package main
    
    import (  
        "fmt"
    )
    
    type author struct {  
        firstName string
        lastName  string
        bio       string
    }
    
    func (a author) fullName() string {  
        return fmt.Sprintf("%s %s", a.firstName, a.lastName)
    }
    
    type post struct {  
        title   string
        content string
        author
    }
    
    func (p post) details() {  
        fmt.Println("Title: ", p.title)
        fmt.Println("Content: ", p.content)
        fmt.Println("Author: ", p.fullName())
        fmt.Println("Bio: ", p.bio)
    }
    
    func main() {  
        author1 := author{        
            "Naveen",        
            "Ramanathan",        
            "Golang Enthusiast",
        }
        post1 := post{        
            "Inheritance in Go",        
            "Go supports composition instead of inheritance",
            author1,
        }
        post1.details()
    }
    
    Title:  Inheritance in Go
    Content:  Go supports composition instead of inheritance
    Author:  Naveen Ramanathan
    Bio:  Golang Enthusiast
    

      

    结构体切片的嵌套

    package main
    
    import (  
        "fmt"
    )
    
    type author struct {  
        firstName string
        lastName  string
        bio       string
    }
    
    func (a author) fullName() string {  
        return fmt.Sprintf("%s %s", a.firstName, a.lastName)
    }
    
    type post struct {  
        title   string
        content string
        author
    }
    
    func (p post) details() {  
        fmt.Println("Title: ", p.title)
        fmt.Println("Content: ", p.content)
        fmt.Println("Author: ", p.fullName())
        fmt.Println("Bio: ", p.bio)
    }
    
    type website struct {  
         posts []post
    }
    
    func (w website) contents() {  
        fmt.Println("Contents of Website
    ")    
        for _, v := range w.posts {
            v.details()
            fmt.Println()
        }
    }
        
    func main() {  
        author1 := author{        
            "Naveen",        
            "Ramanathan",        
            "Golang Enthusiast",
        }
        post1 := post{        
            "Inheritance in Go",        
            "Go supports composition instead of inheritance",
            author1,
        }
        post2 := post{        
            "Struct instead of Classes in Go",        
            "Go does not support classes but methods can be added to structs",
            author1,
        }
        post3 := post{        
            "Concurrency",        
            "Go is a concurrent language and not a parallel one",
            author1,
        }
        w := website{
            posts: []post{post1, post2, post3},
        }
        w.contents()
    }

    在上面的主函数中,我们创建了一个作者 author1,以及三个帖子 post1post2和 post3。我们最后通过嵌套三个帖子,在第 62 行创建了网站 w,并在下一行显示内容。

    程序会输出:

    Contents of Website
    
    Title:  Inheritance in Go  
    Content:  Go supports composition instead of inheritance  
    Author:  Naveen Ramanathan  
    Bio:  Golang Enthusiast
    
    Title:  Struct instead of Classes in Go  
    Content:  Go does not support classes but methods can be added to structs  
    Author:  Naveen Ramanathan  
    Bio:  Golang Enthusiast
    
    Title:  Concurrency  
    Content:  Go is a concurrent language and not a parallel one  
    Author:  Naveen Ramanathan  
    Bio:  Golang Enthusiast
    

      

    使用接口实现多态

    Go 通过接口来实现多态。在 Go 语言中,我们是隐式地实现接口。一个类型如果定义了接口所声明的全部方法,那它就实现了该接口。

    1、多个类型可以实现同一个接口。 
    2、一个类型可以实现多个接口。

    package main
    
    import (
        "fmt"
    )
    
    type Income interface {
        calculate() int
        source() string
    }
    
    type FixedBilling struct {
        projectName string
        biddedAmount int
    }
    
    type TimeAndMaterial struct {
        projectName string
        noOfHours  int
        hourlyRate int
    }
    
    func (fb FixedBilling) calculate() int {
        return fb.biddedAmount
    }
    
    func (fb FixedBilling) source() string {
        return fb.projectName
    }
    
    func (tm TimeAndMaterial) calculate() int {
        return tm.noOfHours * tm.hourlyRate
    }
    
    func (tm TimeAndMaterial) source() string {
        return tm.projectName
    }
    
    func calculateNetIncome(ic []Income) {
        var netincome int = 0
        for _, income := range ic {
            fmt.Printf("Income From %s = $%d
    ", income.source(), income.calculate())
            netincome += income.calculate()
        }
        fmt.Printf("Net income of organisation = $%d", netincome)
    }
    
    func main() {
        project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
        project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
        project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
        incomeStreams := []Income{project1, project2, project3}
        calculateNetIncome(incomeStreams)
    }
    

    在上面的 main 函数中,我们创建了三个项目,有两个是 FixedBilling 类型,一个是 TimeAndMaterial 类型。接着我们创建了一个 Income 类型的切片,存放了这三个项目。由于这三个项目都实现了 Interface 接口,因此可以把这三个项目放入 Income 切片。最后我们将该切片作为参数,调用了 calculateNetIncome 函数,显示了项目不同的收益和收入来源。  

    Income From Project 1 = $5000
    Income From Project 2 = $10000
    Income From Project 3 = $4000
    Net income of organisation = $19000 

    refer:https://studygolang.com/articles/12681

  • 相关阅读:
    解密JavaScript闭包
    如何实现JavaScript的Map和Filter函数?
    JavaScript函数重载
    ES6之Spread Operater拷贝对象
    C#中如果用await关键字来await一个为null的Task对象会抛出异常
    为何使用Microsoft SQL Server Management Studio连接Integration Services服务失败
    EF Core中如何正确地设置两张表之间的关联关系
    EF Core中外键关系的DeleteBehavior介绍(转自MSDN)
    SQL Server下ADO.NET 怎么获取数据库SQL语句INSERT,UPDATE,DELETE了多少行数据
    ASP.NET Core Middleware (转载)
  • 原文地址:https://www.cnblogs.com/-wenli/p/11806203.html
Copyright © 2011-2022 走看看