go语言封装是怎么回事( 五 )


这样就很神奇了,方法的接受者不论是值类型还是指针类型,调用者既可以是值类型也可以是指针类型,为什么?
同样的,基于语义进行分析,方法的设计者和调用者之间可以说是松耦合的,设计者的更改对于调用者来说没有太大影响,这也就意味着以后设计者觉得用值类型接收参数不好,完全可以直接更改为指针类型而不用通知调用者调整逻辑!
这其实要归功于 Go 语言到设计者很好的处理了值类型和指针类型的调用方式,不论是值类型还是引用类型,一律使用点操作符 . 调用方法,并不像有的语言指针类型是 -> 或 * 前缀才能调用指针类型的方法.
有所为有所不为,可能正是看到了这两种调用方式带来的差异性,Go 全部统一成点操作符了!
虽然形式上两种调用方式是一样的,但是设计方法或者函数时到底应该是值类型还是指针类型呢?
这里有三点建议可供参考:

  • 如果接收者需要更改调用者的值,只能使用指针类型
  • 如果参数本身非常大,拷贝参数比较占用内存,只能用指针类型
  • 如果参数本身具有状态,拷贝参数可能会影响对象的状态,只能用指针类型
  • 如果是内建类型或者比较小的结构体,完全可以忽略拷贝问题,推荐用值类型.
当然,实际情况可能还和业务相关,具体用什么类型还要自行判断,万一选用不当也不用担心,更改一下参数类型就好了也不会影响调用者的代码逻辑.
封装后如何访问封装问题基本上讲解清楚了,一般来说,封装之后的结构体不仅是我们自己使用还有可能提供给外界使用,与此同时要保证外界不能随意修改我们的封装逻辑,这一部分就涉及到访问的控制权限了.
Go 语言的访问级别有两种,一种是公开的另一种就是私有的,由于没有继承特性,也不涉及子类和父类之间访问权限继承问题,顿时觉得没有继承也不是什么坏事嘛,少了很多易错的概念!
虽然现在理解起来很简单,具体实际使用上是否便利还不好判断.
关于可见性的命名规范如下:
  • 名称一般使用大驼峰命名法即 CamelCase
  • 首字母大写表示公开的 public ,小写表示私有的 private .
  • 上述规则不仅适用于方法,包括结构体,变量和常量等几乎是 Go 语言的全部.
那么问题了,这里的 public 和 private 是针对谁来说?
Go 语言中的基本结构是包 package,这里的包和目录有区别,并不像 JAVA 语言那样包和目录严格相关联的,这一点对于 Java 小伙伴来说需要特别注意.
包是相关代码的集合,这些代码可能存放于不同的目录文件中,就是通过包 package 的声明告诉 Go编译器说:我们是一个家族整体.
如果不同的文件目录可以声明在同一个包中,这样相当于允许家族外迁,只保留姓氏就好.
还是用代码说话吧,散落在各地的小伙伴能不能有共同的姓氏!
go语言封装是怎么回事

文章插图
 

go语言封装是怎么回事

文章插图
 
pack.go 源码文件和 pack_test 测试文件都位于相同的目录 pack 下且包的声明也相同都是 pack.
这种情况相当于一家氏族位于一个村落中一起生活,和其他语言到表现一致.
现在试一下这个氏族的一部分人能不能搬到其他村落居住呢?
go语言封装是怎么回事

文章插图
 
难不成跨域地域有点大,不支持定义方法吗?那移动一下使其离 pack 目录近一点试试看!
go语言封装是怎么回事

文章插图
 
还是不行,不能新建子目录,那么和原来在一个目录下呢?
go语言封装是怎么回事

文章插图
 
只有这样是可以被标识位结构体的方法的,如果不是方法,完全可以任意存放,这一点就不再演示了,小伙伴可自行测试一下哟!
go语言封装是怎么回事

文章插图
 
"github.com/snowdreams1006/learn-go/oop/pack" 是当前文件中导入依赖包路径,因此调用者能否正常访问到我们封装的结构体.
在当前结构体中的属性被我们设置成了小写字母开头,所以不在同一包是无法访问该属性的.
go语言封装是怎么回事

文章插图
 
封装后如何扩展设计者封装好对象供其他人使用,难免会有疏忽不足之处,此时使用者就需要扩展已存在的结构体了.
如果是面向对象的设计思路,最简单的实现方式可能就是继承了,重写扩展什么的都不在话下,可是 Go 并不这么认为,不支持继承!


推荐阅读