面向对象的代码风格(下)

面向对象代码的结构

在结构化编程中,代码的结构以分解流程,实现处理方案为核心,代码的分解原色是以实现步骤为主。理解这种结构的代码,我们需要先理解问题的解决方案,如果需求变化,一般都需要修改代码。面向对象思想,针对结构化编程的这些缺点,提出了著名的“开-闭”原则。意思是代码应该对添加开放,对修改关闭。能做到这个原则,是需要代码结构上利用面向对象的特性才能做到的。

面向对象代码结构的重点是定义“类”,与结构化编程倾向分解问题解决步骤不同,面向对象编程更重视描述问题本身。由于代码按“类”划分,所以一般不会完全解决本身,而是全面的划分问题本质相关的角色。能做到“对添加开放”的根本原因,是以基类或接口描述了问题的“外观”,而需求的变化一般不涉及问题接口,而是实现的细节,因此利用多态,就能仅仅添加代码以完成增加新的实现代码。

“对修改关闭”主要是通过面向对象的封装特性实现的,我们可以把接口基类和部分实现类编译成库,用户没有源代码就无法修改实现是类,但是他们依然可以继承、实现接口类。只要系统可以提供“注册”具体实现类的接口,就能轻易添加新功能了,而这种“注册”功能,正是所谓Ioc控制反转体系的基本功能。

在设计接口和实现类,以及设计基类和子类时,我们往往会不自觉的把日常生活中的分类方法用于程序设计:把通用的设计基类,把特殊的设计成子类。但实际上这种想法可能会是错误的,正确的设计应该是规则约束少的为基类,规则约束多的为子类。

最著名的例子是矩形和正方形。日常观念中,矩形是比较通用的,而正方形是比较特殊的图形。所以我们很容易把矩形设计成基类,而正方形设计成继承矩形的子类。但是这就是一个错误的设计,因为如果用户以矩形的接口,去使用正方形的实例对象,调用了设置长度、宽度的方法时,其中的一个设置可能就是无效的,因为正方形不能接受不同的长度和宽度。这很容易产生逻辑错误。正确的做法是把正方形作为基类,而矩形继承正方形类,这样“设置边长”的方法也可用于矩形。

我们在设计类的继承关系时,必须注意所谓“一般”和“特殊”的真实含义。由于在面向对象设置中,代码如按此“依赖倒置”原则设计,业务逻辑必将会被继承结构拆分成“一般”和“特殊”的层次结构。此种结构类对比结构化编程,就是把大流程拆分成多层级的子流程。但是,在面向对象的语义下,这种拆分的约束更多,更细致。比结构化编程的指导性更强。

在面向对象程序的结构中,还有一条原则叫“最小知识原则”,此原则要求代码间的耦合尽量简单:函数参数尽量少,引用的类型数量尽量少……。在结构化编程中,我们由于要组合多个函数,就会使用大量的过程变量,这样的代码无论如何简化,都不可能太简单。由于每个函数的调用都不带上下文,因此很多API设计者都喜欢设计常常的参数列表,以便使用者能更“灵活”的使用。但是这样的代码阅读区来宛如天数,即便你熟悉这些API,你也难以从一串参数中一样看出其含义。

面向对象的代码结构,就要破解这种难以阅读的代码:由于每个调用层次的类、方法,都要求“缩小”耦合范围,简化使用形式,所以其类名、方法名就能带上更多语言,从而提高可读性。而这些类可以通过“开闭原则”,被拆分为多个层次的其他组合类,用户可以通过使用这些较低层的类来扩展功能,或直接通过继承来添加新的功能。

面向对象代码建模

面向对象思想是与结构化编程不同的一种思路,但并不是说就一定比结构化更先进。他们的关系应该是平等的。结构化编程思想诞生于计算机早期应用领域,以计算密集型任务为主,应用范围比较集中于需求稳定的领域,比如军事、金融、通信、操作系统;而面向对象这是在计算机应用范围快速扩大之后,大量商业、娱乐业务,需要更多的需求变化能力,因此代码的可读性,修改能力,变得更加重要。

面向对象编程,就是为了这种需求变化而设计出来的。在面向对象方法中,最自然的就是针对业务领域的对象去建模,就是看业务领域中有什么东西,直接用这些东西来建立类。在游戏领域,这种方法最常见,因为游戏世界中本来就有许多虚拟角色、物品、场景。在电子商务这些与现实结合的领域,使用直接映射建“类”也很方便,现实业务领域提供了大量的概念定义。相比之下,结构化编程更依赖于程序的理性思考,对问题做细致分解;面向对象领域程序员有大量业务领域参照物,看起来简单得多。

虽然用直接业务领域映射的方法,很容易满足代码理解的需求,但是并不一定是最优方案。因为需求变更导致的代码修改,并不一定能很简单的对应到业务领域模型上。这就引入了面向爱你个对象思想的另外一个原则:需求变化的原因,就是对象建模的边界。——如果你发现有个需求变化,一定要修改代码,那么这个修改的地方,就是代码应该“切分”耦合的位置。这里的切分,就意味需要有两个不同的类。在需求的不断变化中,好的面向对象程序会逐步“进化”,变得越来越适应真实需求。这和传统的思维:需求变化会让代码“腐化”,是很不一样的。因此说面向对象思想是一种拥抱变化的思想。

在大量的编程实践中,人们总结了23种经典的“设计模式”。归根到底,这些模式利用面向对象的语言机制,更好的应对现实需求变化而产生的手段。设计模式把多种对象间常见的关系模型,抽象成模式。

从直接的业务领域建模,转化成使用设计模式建模,往往需要一些思考分析,幸运的是,设计模式的资料汗牛充栋,而模式本身也就那么几种,全部记住也不是难事。因此,在理解了设计模式的使用条件后,这些知识就比较容易协助开发者建模。从这点上看,结构化编程中对于编程思想的指导就显得抽象的多,因此也更难以被掌握与良好的运用。

在设计模式之上,人们还总结出针对更大型系统的设计经验:架构模式。虽然架构模式不限于使用面向对象特性来实现,但是设计模式却能很有效的用于构建各种架构模式。

在面向对象的实践中,许多思想往往只是一句话,但实现手段则可能很多种,因此业界总结出了:OOP->OOD->OOA三个层次的实践经验,对于新人来说,这无疑是一条明确的升阶之路。这个路径为软件业界提供了大量的优秀人才和作品,因此非常值得推广。

感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。如有不同意见,欢迎后台留言探讨。

原文发布于微信公众号 - 韩大(handa1740168)

原文发表时间:2016-02-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老九学堂

技术大咖分享:如何评价一段代码?

经常有人微信问老九君,什么样的代码才算是好代码。这个问题其实见仁见智,业内也没有统一的标准可以使用。我仔细梳理了一下自己评价代码的方法,总结了五个评价指标。 规...

3366
来自专栏一个会写诗的程序员的博客

“一切皆是映射” (光剑)

这句话背后的意义不仅仅在于函数式编程。量子力学说过,事物只在相互作用时才出现。“事物”即“一切”,“相互作用”即“映射”。这是“一切皆是映射”(光剑)这句话背后...

592
来自专栏IT派

人民日报整版报道区块链,我只想知道用什么语言开发?

IT派 - {技术青年圈} 持续关注互联网、区块链、人工智能领域 2月26日,《人民日报》经济版头条整版刊发了区块链署名评论文章《三问区块链》《抓住区块链这...

7746
来自专栏诸葛青云的专栏

转行的萌新如何学习C语言?应不应该跳过C直接入手C++呢?

很多人对学习C语言感到无从下手,经常问我同一个问题:究竟怎样学习C语言?我是一个高级编程师,已经开发了很多年的程序,和很多刚刚起步的人一样,学习的第一个计算机语...

1224
来自专栏有趣的Python

玩转算法面试:(一)什么是算法面试?

前言 对于面试中遇到的大多数问题 都能有一个合理的思考路径 沟通: 边界条件是怎样的? 数据范围如何? 某些术语是具体如何定义的? ? 基础数据结构 算法设...

3659
来自专栏lgp20151222

Oracle的dual

543
来自专栏IT派

Python学习路线图

Python上手很容易, 基本有其他语言编程经验的人可以在1周内学会Python最基本的内容.

1850
来自专栏非著名程序员

如何评价一段代码

经常有人微信问我,什么样的代码才算是好代码。这个问题其实见仁见智,业内也没有统一的标准可以使用。我仔细梳理了一下自己评价代码的方法,总结了五个评价指标。 1、规...

1679
来自专栏程序员互动联盟

为什么都说java比较容易入门?

说java比较容易入门的人,应该都是正常的人,因为相比之下,java有着不可比拟的优势,对于编程新手来说这个优势,可以让他们更快的用java语言写出他们自己的东...

3278
来自专栏程序员的SOD蜜

“法天象而应四时”--茶话软件开发之“抽象”(2)--过程的抽象:函数

本想写这样的一个系列的,无奈一直没有时间,没想到网上已经有人写了类似的文章,说明了我原来的观点: 函数既是过程的抽象! 当然,函数的抽象意义远非如此简单,这里先...

1889

扫描关注云+社区