面向对象思考与 golang cobra 库实现原理

本文探讨了如何在非面向对象语言Golang中应用面向对象思想,以Cobra库为例,分析了其单例、命令、模板方法和组合设计模式。通过理解Go语言的包装、隐藏、数据抽象等特性,展示了如何实现类似Cobra的可扩展CLI程序。
摘要由CSDN通过智能技术生成

面向对象思考与 golang cobra 库实现原理

golang 不是面向对象的语言 ,在golang中函数是一类成员(First-class function)/知乎解释 。本文不打算纠结 golang 有哪些面向对象特性,仅关注面向对象的思想如何在 golang 中应用,让我们轻松一些写出类似 cobra 中 comamnd.go 这样易于使用、可扩展的程序。

本文要点:

  1. 面向对象设计与编程基本概念
  2. Golang 的与面向对象支持相关的知识
  3. 用设计模式设计 command.go

前提条件:

  1. go tour 练习完成
  2. 使用 flag 包处理简单的 cli
  3. 会用 cobra
  4. 熟悉 C++ 或 Java

环境准备

使用 cobra 创建一个 golang 应用,文件结构

main.go
/cmd
    root.go
    register.go
    delete.go

其中: register 和 delete 命令支持 -u --user=name 参数

1、面向对象设计与编程基本概念

什么是面向对象?

Everything is an Object.

--- Bruce Eckel 《Thinking Java》

对于普通人,面向对象设计与编程是最常见的选择。多年产业实践证明,面向对象具有具有易于理解、易于复用(reuse)和可扩展(extend)的优势。如果我们把世界的一切用函数来理解,这需要你具备更加优秀的抽象思维能力,特别是数学思维能力。Lisp 等语言的成功,证明了以 λ 演算为基础语言的重要性,它更容易高效编写高品质的程序。同样,用顺序、分支与循环这样结构化方法理解计算,则相对机械一些。

面向对象的语言?

对象 作为基本 程序结构单位 的程序设计语言。纯面向对象语言:Smalltalk, Eiffel(埃菲尔),…,Java。 其中 Java 是最成功的程序设计语言,长期排在 TIOBE 编程语言指数排行榜前二位。随着互联网发展,尽管出现了许多新的语言 Golang, Clojure, Scala,Dart 等更挣钱的语言的竞争,Java 目前稳居排行榜第一位, “存在即真理” 的背后,一定有它的道理。

什么是对象

An object is the simulation of an entity in a computer.
An object is an encapsulation of attributes, behaviors and constraints.

对象与现实

面向对象语言的特点

  • 包装 Encapsulation
  • 信息隐藏 Information Hiding
  • 数据抽象 Data Abstraction
  • 继承 Inheritance
  • 多态 Polymorphism

通过上述技术,实现了 Reference System -> Design & Programming

面向对象的设计

设计对象、接口、对象之间的关系,用于解决问题。

设计模式

常见应用场景的涉及的对象、对象外部特征、及其之间关系,以及典型代码。例如:

  • 单例(Singleton)模式
  • 命令(Command) 模式
  • 模板方法(Template methods)模式
  • 组合(Composite)模式

2、Golang 的语言知识与折中(trade off)

函数虽然高雅,但不是一般人容易理解与接受,并写出高品质的程序。运用面向对象的思想在非 OOP 语言中编程,就是必须 get 的技能了。
首先,我们复习一些语言知识,同时讨论 go 语言设计与折中的选择。

2.1 Go 语言的基本元素
  • 数据与数据类型 type
  • 函数 func
  • 包 package

深入理解 Nicklaus Wirth 算法+数据结构=程序 这句话永远不错。

Go的理念: 简单、简单、简单 (没考证 !?对吗?)

  • 数据就是数据,是不可变的。例如:
    • Student 作为数据就是 Student,不是 Person
    • Student 作为对象是 Person
  • 函数是一种类型,值是 First-Class 的
    • 函数类型 = 函数签名 (什么是函数签名?)

Go 是静态类型化的。每个变量都有一个静态类型,也就是说,在编译的时候变量的类型就被很精确地确定下来。

2.2 Go 的包装与隐藏

包导出类型与数据

go 的包装单位是 package。 将包中数据或类型的 第一个字母大写 ,就导出该包中的内容。

包命名

包的全名称是工作区 src 中目录结构的路径(除了语言内置包),短名称就是最后目录名。为了便于编程,包可以使用 别名(alias)
例如,我们不喜欢 go 内置包 flag 处理参数的风格,我们喜欢 POSIX 风格命令行,怎么办?

import (
  flag "github.com/spf13/pflag"
)

搞定啦!你命令行程序不需要修改其他地方了。

实践: 将 delete.go 程序拖到 main.go 所在的目录,运行程序 go run main.go help 结果是?

go 程序文件

包由一些 go 文件构成。一个包中不能出现相同的类型或变量,包括函数名。它不似 java 那样一个文件对应一个对象类型,你必须机智的记住 go 文件中定义的包变量和类型。你可能需要编写 vars.gotypes.go 来集中管理它们,但一个类型、一个变量一个文件也是最佳实践之一。

init() 和 main() 函数

每个 go 文件可以有一个特殊的函数 init(), 它是包中唯一可以重名的函数。包初始化代码必须在 init() 中。

它们的执行顺序是? 参见 go/golang main() init()方法的调用

2.3 数据抽象

基本类型不用解释!

Java 数据抽象仅一类: Object, 它对外呈现一些 interface,对象之间通过消息协作。

Go 要复杂一些:

  • struct
  • func
  • interface
  • specials: chan

methods

go 的方法似乎很有特色,让我们操作数据时有了“面向对象”的感觉。其实,在上世纪面向对象语言Eiffel(埃菲尔) (第二个)就有了啊。感兴趣去看一看

  • var type 语法
  • eiffelThreads vs goroutine 并发
  • static typing

go-method 的确是值得夸赞的创新,它与接口实现了无缝对接。它通过 receiver argument 概念,让不同类型的 operator 具有了相同的函数签名。而一组函数签名相同的操作与接口一致,则实现了接口与数据类型的隐式静态绑定。

type Vertex struct {
   
	X, Y float64
}

func (v Vertex) Abs() float64 {
   
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func Abs(v Vertex) float64 {
   
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
   
	v := Vertex{
   3, 4}
	fmt.Println(v.Abs(), Abs(v))
}

在以上代码中,函数 Abs方法 Abs 语义是一样的,方法可以被认为是“语法糖”。但对于编译,Vertex 类型的数据可 静态 推导到接口类型

type Abser interface {
   
	Abs() float64
}

构造方法

为了实现 struct 的构造,golang 提供了一些编程约定(convention),例如:

  • 提供 NewVertex(v Vertex) *Vertex
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值