浅谈抽象数据类型(ADT)的可变与不可变性

一.什么是可变,什么是不可变?

可变与不可变的讨论我认为可以从以下两个角度来思考:

  • 一种观点是:可变与不可变的区分在于事物(ADT)本身是否能够改变
  • 另一种观点是:可变与不可变的区分在于事物(ADT)是否提供了可以改变自身的方法

这两种观点之间也有着一些联系。

比如,单独的一个ArrayList,由于它本身具有add(),remove()等方法,我们认为其是可变的;但是如果创建一个新类,里面只有一个私有字段ArrayList,是private的,并且不存在任何的表示泄露,甚至没有任何一个方法,虽然ArrayList本身是可变的,但是我们并没有暴露任何可以改变它的方法,那么对我们来说,它似乎也是不可变的。

再比如,一个单独的String类型,我们认为它是不可变的;但是如果将其放入一个ADT中,并提供相应的set()方法,那么它便使该ADT变成了mutable的。

说到这里,可能就有人会糊里糊涂了,那么到底什么是可变,什么是不可变呢?

其实也很容易理解,就像是ADT之间的等价性分为行为等价性和观察等价性两种一样,我认为ADT的可变与不可变也可分为行为与观察两种。

  • 从行为角度看,一个ADT如果有能够使其改变的方法(不管有没有暴露出来),那么它就是mutable的;
  • 而从观察者角度看来,我们并不知道ADT的内部构造,只能够看到其暴露出来的方法,如果其中有mutator,那么该ADT是mutable的。

在实际编程过程中,我们往往不知道ADT的底层实现细节,只能够通过暴露出来的方法,来使用ADT,故我们认为的可变与不可变大多是站在观察者角度的。

如果你看懂了以上内容,那么考虑下一个问题:不可变的的ADT中成员变量一定是使用final修饰的嘛?

很显然,我认为不一定必须要用final修饰(虽然实际编程中经常使用final修饰)。我们通常会使用final来修饰,我认为是因为我们无法保证ADT中绝对不会出现对该成员变量的mutator方法,而并不是因为该ADT的不可变性。

如果我们没有暴露出该成员变量的mutator方法,那么其实用不用final修饰,好像都是一样的,起码在Client端使用该ADT的时候,Client不会认为这是一个mutable数据类型。

综上所述,我认为可变与不可变的划分并没有一个绝对的界限,关键在于你站在什么角度来看待的这个问题。

二.我们什么使用可变数据,什么时候使用不可变数据?

正如ADT的可变与不可变不是绝对的一样,二者在不同角度上也有不同的优劣性。

  • 站在性能的角度上看,那必然是可变数据类型要优越的多。

在生活中,我们身边其实也有很多可变与不可变的例子。例如,我们在使用word时对文章的修改,便是一个可变的例子。即使在文档保存了之后,我们仍然可以对其再次修改,这就是一种可变性;如果文档保存后不可变,那么当我们想要对其修改的时候,就需要重新拷贝一份文件,这不仅浪费了我们的时间,也消耗了硬盘的存储空间。在编程过程中也同样如此,使用不可变数据类型往往存在大量的拷贝,在时间和空间上都不如可变数据类型。

因此,性能上,可变数据类型更胜一筹。

  • 站在安全的角度上看,不可变数据类型又显得可靠得多。

人一出生,性别便是不可变的(呃,变性暂不考虑),如果性别可以随意改变,那必然会引起很多不安全的现象,就像男厕,女厕到底该进哪一个,就很难选择。所以对此种情况,我们往往采用不可变数据类型,保证其不可变性。编程中,那些我们不希望别人可以随便更改的内容,也往往使用不可变的数据类型要安全的多。

还有就是在多线程的编程中,或是多人协作,分布式部署等。我们也往往更喜欢使用不可变数据类型,因为有些数据是共享的,我们无法确保其他线程/人/服务器不对共享数据进行我们不希望发生的更改。

因此,不可变数据类型虽然性能不占优,但是在有些时候,更能使我们安心。

总结

本文主要讨论了抽象数据类型(ADT)的可变与不可变性的区分,以及二者的适用情况,希望能对读者理解ADT的可变与不可变有所帮助。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值