Java国王:我来告诉你什么才是真正的封装!

Java 帝国第一代国王正式登基,百官前来朝贺。

大臣甲说道:“恭喜陛下登基,为了吸引更多程序员加入我国,臣建议尽快完善我们Java语言的OOP特性,封装、继承、多态。”

国王说:“一个个来,先说说封装吧, 我们现在已经可以把数据和方法放到一个类中,接下来想办法隐藏信息,限制对他们的访问了, 我听说现在有不少人在使用C++, 能不能从它借鉴一下啊? ”

大臣乙对C++很有好感,他说:“陛下圣明,C++那里有pubic, private,protected 等关键字,可以用于修饰属性和方法,我们直接拿过来用得了。”

“如此甚好!” 国王表示赞许,不过他眼珠一转,突然想到了早些年出现的Python, 他问道:“Python是怎么处理封装这个问题的?”

大臣甲从Python王国“倒戈”而来,怀着对故国的歉意,十分想把Python的语法带来一点给Java,听到国王这么问起,赶紧说到:“Python的处理比较简单,用两个下划线来表示私有的属性和方法。”

可是国王却说:“嗯,这种方式挺简单的嘛,用下划线就实现了,很简洁,我们能不能也这样啊?”

大臣乙有点瞧不起这个脚本语言,他赶紧说:“万万不可,陛下有所不知,这个Python啊,即使加了下划线,也只是‘伪私有’的属性和方法。”

“什么是伪私有?”

“就是说外界依然有方法访问他们!”

“这算哪门子私有的属性和方法? 一点都不纯粹。” 大臣乙继续补刀。

国王说:“好吧,那不学它了, 那JavaScript呢?他是怎么实现封装的?”

朝中的大臣们面面相觑,JavaScript? 这是什么鬼?怎么没有听说过?

(码农翻身注:JavaScript的出现时间比Java要晚, 这个Java国王估计是穿越了。)

把类隐藏起来

大臣甲看到自己的想法没有“得逞”,又另辟蹊径:“陛下,Python有module的机制,可以把多个类组织到一起,形成一个高内聚的单元,我们Java要不也这么干?”

国王瞪了大臣甲一眼,训斥道:“不要什么都学Python! 我们也得有点独特的东西啊。对于如何组织class, 我们可以用package,一个package对应文件系统的一个目录,下面可以有多个class文件。如果一个类没有被public 修饰,那他只能被同一个package下面的类访问,其他package的类是访问不到的。这个设计不错吧?!”

国王甚为得意。

同一个package下有三个类A,B,C, 只有class A能被外边的包访问到,可以充当这个包对外的“接口” (注:不是java 的interface ), B,C只是包级可见的类, 相当于包内部的实现了,外界是无法new 出来, 防止了被外界误用。

只要保证A不发生变化,就不会影响外界使用, B和C想怎么改就怎么改!

类的朋友

大臣甲小心地问道:“如果我只想把foo.core中的class B暴露给foo.cmd访问,同时阻止别的包访问class B,该怎么办呢? ”

“怎么会有这么‘变态’的需求? ” 朝中各位大臣都表示不可思议。

国王沉吟道:“程序员的要求是无穷无尽的,例外总是会发生的, 这种需求是存在的, 容朕想想。”

熟悉C++的大臣乙赶紧上奏:“陛下,C++ 有个什么friend class的概念。 例如在class Node 中声明了 friend class LinkedList , 那LinkedList 就可以访问Node 类的属性和方法了。 ”

大臣甲强烈反对这种做法:“不好不好,虽然看起来给程序员提供了方便,但是给封装性撕开了一个大口子,如果被滥用,后果不堪设想。”

国王表示同意:“对,还是放弃这种想法吧,保持简单性最重要。 如果他实在想访问class B,可以采用两种办法:(1) 把 class B 变成 public (2) 通过接口class A来进行代理。”

模块化

斗转星移,转眼间Java国王已经传到了第9世。

这一天,邻国的Python, JavaScript派使者来访,受到了国王的热情招待,席间谈到了java package的存在的问题。

Java package的方式虽然不错,可是还是有很大的弊端,其中最大的弊端就是很多包中的类都是public的, 这就造成了这样一种情况。

JavaScript使者说道:“奥, 我原来以为贵国的一个jar文件就是一个可复用的模块, 现在看来还是远远不够啊!”

“怪不得大家都说,你的一个jar文件就是class的压缩包, classpath就是把这些类给平铺而已。” Python使者笑道。

Java国王心中有点生气,但是脸上没有表露出来:“贵国是怎么实现的啊?”

Python使者想了想, 自家的module好像也差不多,并且只能靠约定(给变量和方法的前面添加下划线)的方式来实现private , 由于是约定的,外界依然可以访问。

JavaScript想到自己连module, package都没有,赶紧噤声。

Java 国王说:“简单的jar文件缺乏一个重要的特性:隐藏内部实现, 寡人打算做一个重要的改变,定义真正的模块!”

“看到没有? 我打算用一个文件module-info.java来定义一个模块中有哪些包是可以被export的,只有那些export的包才能被Client所调用, 其他的包对Client都是不可见的。 ”

看到这个设计方案,各个大臣都觉得不错。 有了模块, 就真正地定义了对外可以访问的接口,除了接口的那个package之外,其他的package是不可访问的, 彻底实现了封装。

ServiceLoader

Python使者盯着这个图看了一会儿,说道:“不对吧,假设有这样的代码:”

FooService service = new FooServiceImpl();

Java国王心想这Python使者对我Java语言挺熟悉的啊,搞得我下不来台。

Python使者却继续施压: “不过让人不爽的是, 这个FooServiceFactory虽然属于api包,但是需要知道impl包的具体实现。 如果想添加一个FooService的实现,还得修改它。还是不妥啊!”

突然,Java国王拍了一下脑袋,对了,我怎么把ServiceLoader给忘记了呢?

Python使者还是不太明白: “那客户端怎么使用呢?”

“简单,Client 代码可以这么写:”

这样在运行时,Client的代码就可以使用ServiceLoader就可以找到这些具体的实现了, 当然实现可能不仅仅只有一个,Client选择一个就可以了。

当然,JDK必须得实现这个ServiceLoader,去获取这些具体的实现。

“这个方案,即不破环封装性,又提供了足够的灵活性,相当于在运行时装配对象,陛下圣明!” 大臣们纷纷拍马屁。

Python使者见状,也就不再发言,开始低头喝酒。

JavaScript 使者半天都没有开口了,他心里一直在琢磨,我是不是有点落伍了? Python有模块,Ruby也有模块,这Java的模块化更是搞得如火如荼。模块化极大地提升了封装性,如果想进行大型项目的开发这模块化是少不了的, 想想自家那凌乱不堪的js文件, 是时候做出改变了......

(完)

●编号779,输入编号直达本文

●输入m获取文章目录

推荐↓↓↓

算法与数据结构

更多推荐《18个技术类公众微信》

涵盖:程序人生、算法与数据结构、黑客技术与网络安全、大数据技术、前端开发、Java、Python、Web开发、安卓开发、iOS开发、C/C++、.NET、Linux、数据库、运维等。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180904B0FK5U00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券