Go语言之封装

Golang是一门非常优秀的编程语言,它提供了一些非常强大的功能,其中之一就是封装。封装是一种面向对象编程(OOP)的概念,它指的是隐藏对象的内部细节,使得对象只对外暴露必需的行为,提高了代码的安全性和可维护性。

封装的实现步骤如下:

  • 将结构体名、结构体字段、变量等的首字母小写,不能导出,其他包无法使用,变为私有
  • 给结构体所在包提供一个工程模式的函数,首字母大写。类似构造一个函数
  • 提供一个首字母大写的Set方法(类似其他语言的public),用于对属性判断并赋值
  • 提供一个首字母大写的Get方法(类似其他语言的public),用于获取属性的值     

下面我们定义一个日期结构体,包含三个字段年月日,然后实例化赋值,如图:

从上图可以看出,年月日可以随意设置,这根本不符合安全性原则,任何人都可以设置,可以设置任何值,年可能被设置为0到-999,月可能被设置为1-1000,日也可能被设置为1-888,因此我们需要对这些进行封装,以保证数据的安全和准确

setter方法

可以针对date结构体字段来定义对应的方法,比如SetYear、SetMonth、SetDay方法来接受值,在方法中进行判断,如果是有效值,就赋值给结构体字段,否则报错,这类方法常被称为setter方法,依照惯例,Go的setter方法名为SetX的形式,X是你想要设置的东西的名称

下面定义一个SetYear方法,然后接受参数来设置year的值,如图:

从上图看出,通过SetYear赋值后,原结构体的字段year的值还是初始值0,这是因为go的方法默认是值传递,我们修改的是拷贝后的值而不是原值,因此如果要修改原值需要使用指针传递,如图:

再次打印,可以发现原始值也修改了,如图:

上面的SetYeaer方法里我们只是简单的设置了字段值,并没有做条件判断,可以在里面做一些判断年月日的操作,我们先看下main()函数中,及时我们使用了SetYear并在其中加入了判断方法,但是还是可以直接使用date.year来设置值,并且这个后设置的值会覆盖SetYear中的值,如图:

从上图看出,还是会被设置无效值,怎么解决这个问题呢,此时就可以使用封装了

我们可以将上述的结构体和方法都单独放一个包gong中,然后将结构体的字段小写,这样就不可导出,只将方法导出,并添加一个工程函数,封装后更新值只能通过Setter方法,程序被保护了,避免输入无效数据

下面在gong包中定义结构体以及方法,结构体和字段不可导出,通过方法定义,如图:

  • 第8行:定义工程函数,返回实例化后的结构体指针类型
  • 第13、14行:结构体名和字段都小写,因此不可导出
  • 第18行:定义SetYear方法,接收值并判断
  • 第25行:Year方法实际为getter方法用于获取值

注意:未导出的变量、struct字段、函数、方法等仍然能够被相同包的导出的函数或者方法访问

定义主函数,然后调用gong包中的函数并设置值和获取值,如图:

  • 第10行:调用gong包中的函数Date(),获取实例化后的结构体指针
  • 第12行:调用SetYear方法设置年份,如果不符合上面条件会返回错误
  • 第17行:获取设置的年份的值

运行结果如下:

注意:上述例子不用工程函数其实也可以,只需要将结构体data改为Date,那么结构体就可以导出,然后实例化并调用方法即可

getter方法

getter方法一般用于获取值,上面在setter方法的使用例子中我们已经使用了getter方法,就是Year()这个方法,为什么不写成GetYear()呢,其实Go语言允许你这样写,但是不推荐,推荐的是在getter方法前面去掉Get前缀

内嵌

结构体内嵌后,外层结构体是可以访问内层结构体可导出的方法的,对于未被导出的字段和方法是不可访问的

1、修改上面例子,定义新的结构体ImDate,将date结构体内嵌,如图:

在主函数中实例化结构体ImDate,然后可直接调用date中的可导出方法,如图:

如果请求未被导出的字段,将会报错如下:

date.year undefined (type gong.ImDate has no field or method year, but does have Year)

标签