写点什么

设计模式必须通过面向对象来实现吗?

2013 年 2 月 14 日

陈皓之前为微博上发表了观点:“那 23 个经典的设计模式和 OO(面向对象)半毛钱关系没有,只不过人家用 OO 来实现罢了……OO 的设计模式思想和 Unix 的设计思想基本没什么差别”,结果引来了一点点争议,于是,他在“酷壳”上通过文章说明了自己的观点。

陈皓在文章开头首先举例解释了什么是设计模式:

在正式说明 GoF 的那 23 个经典的设计模式其实和 OO 关系不大并和 Unix 的设计思想很相似的这个观点之前,让我先来说说什么是模式?设计模式的英文是 Design Pattern,模式是 Pattern 的汉译。所谓 Pattern 就是一种规则,或是一种模型,或是一种习惯。Pattern 这个东西到处都是,并不只有技术圏子里才有。

接着,陈皓发表了自己的看法:《设计模式》这本书中,GoF 这四个人总结了 23 个经典的面向对象的设计模式,某中有 5 个创建模式,7 个结构模式,11 个行为模式。很多人都会觉得这是面向对象的设计模式,很多人也觉得非面向对象不能用这些模式。我觉得这是一种教条主义。就像《那些流行的编程方法》中的“设计模式驱动型编程”一样,就像《如此理解面向对象》一样的那么的滑稽。回到我的论点——“GoF 的这23 个设计模式和OO 关系不大,并且和Unix 的设计思想基本一致,只不过GoF 用OO 实现了它们”,就像我上面说过的那些生活中的Pattern 一样,只要你仔细思考,你会发现这23 个设计模式在我们的生活和社会中也能有他们的身影。而且也一样可以用OO 的方式实现之。

陈皓针对23 个经典的设计模式中的几个常用的模式做出了自己的解读。

Factory 模式

这个模式可能是是个人都知道的模式。这个模式在现实社会中就像各种工厂一样,工厂跨界的不多,基本上都是在生产同一类的产品,有的生产汽车,有的生产电视,有的生产衣服,有的生产卫生纸……基本上来说,一个生产线上只有做同一类的东西。这和 Factory 模式很相似。编程中,像内存池、线程池、连接池等池化技术都是这个模式,当然,Factory 给你的一个对象,而不单单只是资源,factory 创建出来的对象都有同样的接口可以被多态调用。这其实和 Unix 把所有的硬件都 factory 成文件一样,并提供了 read/write 等文件操作来让你操作任意设备的 I/O。

Abstract Factory 模式

抽象工厂这个模式是创建一组有同一主题的不同的类。这个模式在现实社会当中也有很多例子,比如:

  • 移动公司的合约机计划,88 套餐(通话 100 分钟,短信 100 条,彩信,20 条,上网 200M),128 套餐(通话 200 分钟,短信 150 条,彩信 50 条,上网 500M)……

  • 家里的装修,总是要有厨卫,有门,有灯,有沙发,有茶几,有床,有衣柜,有电视,有冰箱,有洗衣机……,这些都是必需的,只是每个家庭里的具体装修不一样。

  • Diablo 游戏中的 Normal,Hard,Nightmare,Hell 模式,这些模式的怪和场景和故事情况都差不多,就是每个场景的怪物和装备的属性不一样。或是 WarCraft 中的地图就是一个 Abstract Factory 模式 (注:Warcraft 的地图什么都能干)。这和学校中的小学,初中,高中,大学差不多,都是一样的学习环境,一样的教学方式,一样的教室,都要期中考和期末考,都有班长和科代表,就是学的东西的难度不一样,但基本上都是语文、英语、数、理、化。学校就是一个抽象工厂。

这就是抽象工厂的业务模型(或是:Business Pattern),你觉得是不是不一定非要用 OO 来实现这样的模式?(我们思考一下,我们会不会被先入为主了,觉得不会 OO 都不知道怎么实现了),不用 OO,用相同格式但内容不同的配置文件是不是也能实现?在 Unix 下,抽象工厂这个模式在 Unix 下就像是 /etc/rcX.d 下的那些东西,1 代表命令行单用户,2 代表命令行多用户,3 代表命令行多用户完整模式启动,5 代表图形界面启动,0 代表关机,6 代表重启,你要切换的话,init 就行了。

Prototype 模式

原型模式,复制一个类的实现。这个模式在现实中的例子也有很多:传真,复印,都是这个模式。Unix 进程和 Github 项目的 Fork 就是一种。进程 fork 明显不是 OO 的模型(参看:关于Fork 的一道面试题)。用非OO 的方法同样可以实现这个模式。

Singleton 模式

单例模式。生活中,公司只有一个 CEO,法律限制你只能有一个老婆,你只能有一个身份证号,一个 TCP 端口只能被一个进程使用,等等。软件开发方面,并不一定只有 OO 才能做到,你可以用一个全局变量,一个中心服务器,甚至可以使用行政手段来约束开发中不会出现多个实例。Unix 下实现单例进程的一个最常用的实践是在进程启动的时候用“(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)”模式打开一个“锁文件”。

Adapter 模式

适配器模式。可以兼容欧洲美国中国的插头或插座,万能读卡器,可以播放各种格式多媒体文件的插放器,可以解析 FTP/HTTP/HTTPS/ 等网络协议的浏览器,可以兼容各大银行的银联接口、支付宝、Paypal、VISA 等银行接口,可以适配各种后端的解释器的 Nginx 或 Apache,等等。用非 OO 的编程方式就是重新包装成一个标准接口。这个模式很像 Unix 下的 /dev 下的那些文件,操作系统把系统设备适配成文件,于是你就可以使用 read/write 来进行读写了。

Bridge 模式

桥接模式。这个模式用的更多,比如一个灯具可以接各种灯泡或灯管,一个电钻可以换上不同的钻头来适应不同的材料,一辆汽车可以随时更换不同的轮胎来适应不同的路面,你的桌面可以随时更换一个图片来适应你的心情,你的单反相机可以更换不同的镜头来拍不同的照片…… 桥接模式说白了就是组件化,模块化,可以自由拼装。在 OO 中,其主要是通过让业务类组合一个标准接口来完成,这在非 OO 的程序设计中用得实在是太多了,主要是通过回调函数或是标准接口来实现。这个也是 Unix 设计哲学中的主要思想。在 Unix 中,文件的权限使用的就是 Bridge 模式,标准接口是用户,用户组和其它,rwx 三个模式,然后用 chmod/chown 改一改,这文件就有不同的属主和属性了。

Decorator 模式。

装饰模式。这个模式在生活中太多了,你给你的手机或电脑贴个什么,挂个什么,吃东西的时候加点什么佐料,多点肉还是多个蛋,一个 Unix/Linux 命令的各种参数是对这个命令的修饰,等等。我觉得这个模式在 Unix 中最经常的体现就是通过管道把命令连接起来来完成一个功能,比如:ps -elf 是列进程的,用管道 grep hchen 就可以达到过滤的目的,grep 的逻辑没有侵入 ps 中,grep 修饰了 ps,但是其组合起来完成了一个特定的功能。可见,这和 OO 没有什么关系。

Facade 模式

这个模式我们每个人从会编程的时候就在无意识地用这个模式了。这个模式就是把一大堆类拼装起来,并统一往外提供提口。在现实生活中这样的例子太多了,比如:旅行社把机票,酒店,景点,导游,司机,进店打了一个包叫旅行;IBM 把主机、存储、OS、J2EE、DB、网络、流程打了个包叫企业级解决方案。Unix 中最典型的一个例子就是用 Shell 脚本组合各种命令来创造一个新的功能,这是的 Shell 中的各种命令通过标准 I/O 这个接口进行组合交互。

此外,陈皓还讨论了Proxy 模式Chain of Responsibility 模式Command 模式Observer 模式Strategy 模式,读者可以查看原文

最后,陈皓总结道:我们会发现上面 OO 搞出来的那么多模式在 Unix 下看来好像没有那么复杂,而且 Unix 下看起来并没有那么多模式,而且 Unix 中的设计模式无非就是这么几个关键词:单一,简洁,模块,拼装。我们再来看看 OO 设计的两大准则:1)钟情于组合而不是继承,2)依赖于接口而不是实现。你看,Unix 和 OO 设计模式是不是完美的统一吗?

2013 年 2 月 14 日 21:144339
用户头像

发布了 501 篇内容, 共 211.4 次阅读, 收获喜欢 21 次。

关注

评论

发布
暂无评论
发现更多内容

不一样的面向对象(二)

书旅

php 面向对象

架构师训练营第 1 期第 2 周学习总结

du tiezheng

极客大学架构师训练营

Go中的HTTP请求之——HTTP1.1请求流程分析

新世界杂货铺

go golang HTTP Go web

TensorFlow 篇 | TensorFlow 2.x 基于 Keras 模型的本地训练与评估

Alex

tensorflow 模型训练 keras

程序执行太慢?快来学习SIMD加速技术,这个案例下的加速效果我也没想到(附带动手实验)

Optimize-Lab

go 优化代码 优化技巧 开源社区 simd

三步带你开发一个短链接生成平台

Geek_Willie

Java SpreadJS Node

java安全编码指南之:可见性和原子性

程序那些事

Java java安全编码 java编码指南 java安全编码指南

永续合约系统开发源码,区块链合约交易所搭建

WX13823153201

Python 自动化测试全攻略:五种自动化测试模型实战详解

Geek_Willie

自动化测试

Redis做分布式锁可能不那么简单

架构师修行之路

分布式 分布式锁

巡展2020第十三届亚洲国际物联网展览会-南京站

InfoQ_caf7dbb9aa8a

监控应用,应该监控什么?

小清新同学

云计算 运维 监控

MySQL varchar类型最大值,原来一直都理解错了

flyer0126

MySQL varchar

自己动手写SQL执行引擎

无毁的湖光

Java MySQL 数据库 Linux 算法

架构师训练营第 1 期第 2周作业

du tiezheng

极客大学架构师训练营

高难度对话读书笔记—认知篇2

wo是一棵草

关于Java 编译Servlet或者自定义Tag,引入包的问题

谷鱼

Java

关于Java Servlet找不到自定义包或者第三方包

谷鱼

classes

上班路上也是一道美景

xcbeyond

生活 摄影 摄影征文

缓存解决方案-技术专题-Caffeine Cache

李浩宇/Alex

使用Grafana + simpod-json-datasource快速搭建数据看板

诸葛小猿

Grafana 数据可视化 simpod-json-datasource

面试官:讲讲Redis的五大数据类型?如何使用?(内含完整测试源码)

冰河

redis Jedis JedisCluster

如何设计Go语言中的channel

soolaugust

go channel goroutines

架构师训练营第 2 周作业

netspecial

极客大学架构师训练营

问世间异步为何物?

架构师修行之路

微服务 异步

收藏+下载!Flink 社区最全学习渠道汇总

Apache Flink

flink

项目实战,动态增删form表单

麦叔

jquery 克隆

甲方日常 22

句子

Vue 工作 随笔杂谈 日常

如何快速制造OOM

Since

JVM OOM

让世界为之赞叹的开源项目,除了Linux,你知道Git吗?

小Q

Java git 学习 程序员 面试

Dolphinscheduler系统架构设计

dll

Apache DolphinScheduler

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

设计模式必须通过面向对象来实现吗?-InfoQ