查看原文
其他

领域驱动专家张逸文字脱口秀:简单工厂不简单

The following article is from 逸言 Author 我是张逸


马丁花背着灰色的双肩背包走进了公司写字楼,浮现在眼前的是排成长蛇状的一群上班族,正按照单双层各自分成两队等候着电梯。低楼层的童鞋等不及了,甩开双腿开始爬楼梯,就当是减肥锻炼身体了,不着急的依旧排在队伍里,低头看着手机,玩着游戏或者刷着朋友圈。手机扫去了等待的急躁与不安,一个个安静如花,只待电梯像殷勤的主人把他们一批一批接走。

终于踏进了电梯,马丁花被挤到了角落里,电梯里的人互不相识,肃穆像开追悼会,只听得电梯不断发出“叮”的一声响,电子合成声开始汇报多少层到了,门打开,随着不断有人走出,空间变得逐渐开阔起来。

“十八层到了!”自从新搬到这栋写字楼后,马丁花每次听到呆板而不带感情的电子合成声汇报所在楼层到达时,都忍不住翻一下白眼,心里不由脑补出“地狱”两个字眼儿。摇摇头,缓缓走出电梯。

刷卡。自动门刚一打开,就瞥见一道身影正要到正前方拐角处的茶水间倒水,看见自己来了,又赶紧退了回去,似乎故意躲着马丁花。这道身影再熟悉不过,自然躲不过马丁花敏锐的法眼,赶紧叫到:“蔡了!”

“啊……这么倒霉,一上班就被头儿盯住了,昨天布置的作业没完成,怎么办!”蔡了内心不由哀嚎,听到马丁花的声音,只得停下来,无奈装出一副笑脸,言不由衷地说道:“老大,早上好啊!”

“躲着我啊!昨天的作业没做,对吧?”马丁花看到她一副强颜欢笑的样子,哪还不知道古灵精怪的她打的甚么主意,即刻开启了严师模式。

“哼,勤奋如我怎么会没有完成作业呢?”蔡了赶紧辩解,“——只是,我虽然搞清楚了静态工厂实际用的是简单工厂模式,却不知道它能给设计带来什么好处?查了好多资料,发现居然有各种各样的工厂模式,不看还好,越看越糊涂了!”

“嗯,看来你还是做了些功夫的。一会开完站会,到我工位来,我给你简单讲一讲吧!”

蔡了点点头,谢过马丁花,径直到茶水间倒水去了。

站会一开完,蔡了就规规矩矩前来受教。马丁花开门见山,直截了当地说到:“工厂在设计模式中,其实就是一种比喻,目的自然是为了更好地创建对象。既然在Java中已有构造函数能够担负实例化的职责,为何还需要引入工厂呢?要明白工厂的价值,你就需要先明确构造函数的缺陷,对吧?”蔡了不由得点头称是,似乎得到了一丝启发。

“你想想,Java语法中构造函数是怎么定义的?它有哪些语法上的限制?”马丁花循循善诱地提出了问题。

蔡了在脑海中搜索着这段时间学习的Java语法,心里组织着语言,回答道:“类的构造函数与类名必须保持一致;构造函数支持方法重载,但不允许出现相同方法签名;每个具体类的构造函数都只能创建类自身;如果定义了带参构造函数,且又需要无参构造函数,还需要显式定义无参的构造函数。”

“不错!语法记得很清楚。那么,根据这些语法限制,你想想:如果需要创建代码给出清晰的创建目的,构造函数能不能做到?如果创建的对象有可能发生变化,构造函数能不能做到?如果希望控制对象的创建逻辑,构造函数能不能做到?”

“好像是这么回事,不过大叔啊,你可否给我个例子,这样枯燥的理论讲解让人很难理解呢。”小姑娘有些得寸进尺了。

“好吧。”马丁花看着她一脸困惑的样子,无奈地摇摇头,打开IntelliJ,找到JDK中的Optioanal<T>类,展示给蔡了:


“你看JDK 8提供的Optional<T>类,它就定义了诸如empty()、of()和ofNullable()这几个简单工厂,它们创建的虽然都是Optional<T>对象,可相较于直接调用构造函数,它们有什么价值?”

蔡了陷入沉思中。马丁花提醒道:“还是昨天那句话,你要学会站在调用者的角度看待API设计。”这么一说,小姑娘就回过味来,说道:“对啊,有了这些简单工厂,就能更加清晰地告诉调用者究竟创建了什么样的Optional对象,尤其那个empty(),实在太传神了!这实际上就是可读性的要求嘛,很好理解哟。”马丁花看着她一副不屑一顾的样子,想到她刚才一脸茫然抱怨不好理解,真恨不得给她脑门上来一记头粟!

蔡了倒是没来得及察言观色,继续想着老马刚才问的几个问题,想不通,只得问道:“嘿,大叔,你刚才说控制对象的创建逻辑,我有些不清楚,构造函数就是方法啊,难道还不能控制创建的逻辑?”

“如果创建逻辑只是验证、组装、计算等逻辑,构造函数确实办得到;但是,你注意到没有,Java类的构造函数是没有return的,如果你希望控制对象创建的次数,又或者希望引入缓存提升创建对象的性能,构造函数还能做到吗?更不用说,在有些情况下,如果需要通过反射创建对象,就更需要引入静态工厂方法来封装对象创建的逻辑了。”

“例如有Composer继承体系。”马丁花绘制出如下类图:


“考虑Composer的扩展性,需要通过反射创建各个Composer实现类,类名遵循格式:文件扩展名+Composer,你想想看,可以通过YamlComposer或其他实现类的构造函数来完成吗?”

蔡了使劲摇头!马丁花把一段示例代码打开,指着代码继续讲道:“这个时候,就需要引入一个专门的工厂类,为其定义一个静态工厂方法,用来封装创建逻辑。”


“大叔!”蔡了认真看着这个案例,忽然灵机一动,想到一点,赶紧指出来:“那你说的创建对象有可能发生变化,是不是也属于这种情况啊?”

“孺子可教!”马丁花很高兴看到蔡了能够触类旁通,继续讲道:“刚才说到的Composer对象的创建之所以引入反射,确实考虑到了创建对象的变化,不过,在多数情况下,不一定要使用反射来解决这一问题。只要你希望调用者无需了解产品对象创建变化的逻辑,在工厂方法返回父类产品的前提下,你都可以使用简单工厂。例如JDK中的Collections类,就定义了许多静态工厂方法,用于创建Collection<T>对象。创建的这些对象可能是不同的集合类型,但对于调用者而言,可以不必知道产品对象的具体类型。”马丁花一边说着,一边打开Collections类的定义,将光标快速移到unmodifiableCollection()方法上:


“你看!unmodifiableCollection()方法表面上返回的是一个Collection<T>对象,实际上,在其内部定义了一个内部类UnmodifiableCollection,它屏蔽了集合的修改功能,使之成为一个不可修改的集合。你想想看,这样做的好处是什么?”

“嗯……”思索良久,蔡了想到了答案:“我想,这样做应该有两个好处。一个好处是unmodifiableCollection()方法清晰地向调用者传递了创建不可变集合的语义,另一个好处是将来如果修改了UnmodifiableCollection内部类的定义与实现,也不会影响到该工厂方法的调用者。我说的对吗,马大叔?”

“不错,不错!我看你彻底理解了简单工厂的含义!”

“噢耶!”得到马大叔的肯定,蔡了不由得欢呼起来,不过想到其他工厂模式,又苦下脸来,说道:“可是——我还是不太明白简单工厂模式与工厂方法模式、抽象工厂模式的区别和使用场景呢。”

马丁花想了想,指着茶水间,向蔡了说道:“说了半天,口也渴了,不如我们去那边冲一杯咖啡,边喝边讲,如何?”蔡了点点头,和马丁花一起走到了茶水间的咖啡机旁。



☼ 屐痕处处:2019年1月19日摄于法国巴黎

- EOF -


想要加入中生代架构群的小伙伴,请添加群合伙人大白的微信

申请备注(姓名+公司+技术方向)才能通过哦!


技术人成长精彩文章推荐

阿里高级技术专家宋意:平凡人在阿里十年的成长之旅

RocketMQ 大神丁威亲述参与开源社区的方式

多隆:从工程师到阿里巴巴合伙人

为什么说IT科技公司应该留住35岁员工?

工程师的基本功是什么?如何练习?听美团技术大咖怎么说

美团技术专家云鹏:写给工程师的十条精进原则!

找CTO杜仲:再谈中年危机和应对策略

阿里合伙人范禹:常挂在阿里技术人嘴边的四句土话

Erik Dietrich:二十年的编程,教会我的五件事!

支付宝研究员兼OceanBase总架构师杨传辉:我在数据库梦之队的十年成长路

Mobvista首席架构师蔡超:工作感悟之失败与成功,我的8点总结

奈学教育CEO孙玄:成为一个有情怀的工程师,我的12点思考

Netstars CTO陈斌:架构师的成长之路

阿里技术专家麒烨:修炼测试基本功

左耳朵耗子:程序员如何把控自己的职业?

阿里6年,我的技术蜕变之路!

程序员管理思维修炼,只需要反复阅读本篇

“教授”洪强宁和他穿越的技术江湖

大神手把手教你投身技术18年而没有中年危机的秘诀

阿里合伙人程立:阿里15年,我撕掉了身上两个标签

CTO 技术管理的“三板斧”

技术管理者必备管理模板

张一鸣:优秀年轻人的五个特点

技术团队的工程师文化:效率与价值

美团大咖:程序员35岁前应做好的技术积累

史海峰:万字长文剖析技术人如何成长


   END     

#架构师必备#

点分享点点赞点在看
: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存