如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

2023-02-05 0 776

一、程序语言是甚么

程序语言 (Object Oriented,OO) 的价值观对应用软件设计十分关键,它的基本概念和应用应用领域即使已胜过了面向对象和应用软件设计,扩展到如关系数据库、互动式介面、应用应用领域内部结构、应用应用领域网络平台、分布式系统、系统管理内部结构、CAD 控制技术、人工智慧等应用领域。程序语言是一类 对现实生活当今世界认知和抽象化的方式,是计算机系统程式设计控制技术产业发展到很大期后的乙醛。

面向全国操作过程(Procedure Oriented) 是一类 以操作过程为服务中心 的程式设计价值观。那些都是以甚么已经开始出现为主要就最终目标展开程式设计,有别于程序语言的是谁在受负面影响。与程序语言显著的相同是 PCB、承继、类。

不论是在应用软件设计却是在前述组织工作中,深入细致地认知应用软件设计的价值观都十分有必要。

二、从这场赛事讲起

在两个应用软件镇里

有一位现职「面向全国操作过程」开发人员——老过

和一位「程序语言」教徒——阿对

与此同时雇用于一间挨踢店

有一天老板娘灵机一动

下定决心让这三名开发人员展开一场赛事

优胜者将赢得两个限量版的

360 度半自动跑步机

程式设计赛事开始了

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

不一会,他俩都写出了几乎相同的代码

class Bill{ fun getPrice(): Double { val unit = getUnit() val number = getNumber() val price = unit * number return price } fun getUnit(): Double { } fun getNumber(): Int { } }
如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

老过看到新需求,微微一笑

class Bill{ fun getPrice(): Double { val unit = getUnit() val number = getNumber() val price = unit * number if (todayIsLoversDay()) { return price * 0.77 } return price } fun getUnit(): Double { } fun getNumber(): Int { } fun todayIsLoversDay(): Boolean { } }
如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

​他下定决心让新的收银方式承继 Bill 类

先在 Bill 类中新增 discount 方式

并将其开放

open class Bill{ fun getPrice(): Double { val unit = getUnit() val number = getNumber() val price = unit * number return discount(price) } // 处理打折优惠 open fun discount(price: Double): Double{ return price } fun getUnit(): Double { } fun getNumber(): Int { } }

普通的收费方式在 discount

​函数中直接返回价格

七夕节的收费方式则承继此类

在 discount 函数中实现打 77折

class LoversDayBill : Bill(){ override fun discount(price: Double): Double { return price * 0.77 } }

当老过和阿对与此同时将程序交给老板娘时

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

老过已经开始幻想自己将来

坐在跑步机上的舒服日子

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

听到新需求

老过一阵头大

不由在群里吐槽

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

吐槽归吐槽

老过在 getPrice 函数中

再次增加了条件判断

class Bill { fun getPrice(): Double { val unit = getUnit() val number = getNumber() val price = unit * number if (todayIsLoversDay()) { return price * 0.77 } if (todayIsMiddleAutumn() && price > 399) { return price 200 } if (todayIsNationalDay() && price < 100) { // 生成 0 ~ 9 随机数字,如果为 0 则免单。即:十分之一概率免单 val free = Random().nextInt(10) if (free == 0) { return 0.0 } } return price } fun getUnit(): Double { } fun getNumber(): Int { } fun todayIsLoversDay(): Boolean { } fun todayIsMiddleAutumn(): Boolean { } fun todayIsNationalDay(): Boolean { } }

看着越来越复杂的

Bill 类和 getPrice 方式

老过眉头紧锁

他深知事情远没有结束

中秋和国庆一过

他还需要到这个复杂的类中

删掉打折的方式

天知道老板娘还会再提

甚么天马行空的需求

不论是新增或删除代码,在这个过长的类里做修改都是件不太愉快的事。为了在两个很长的函数中找到需要修改的位置,「面向全国操作过程」使得老过不得不浏览大量与修改无关的代码,小心翼翼地修改后,又要反复确认不会负面影响到类的其他部分。

老过在心底里默默地祈祷

这个类不再需要修改

提交了自己的程序

阿对收到新需求时

先是新增了中秋节支付类

class MiddleAutumePrice : Bill() { override fun discount(price: Double): Double { if (price > 399) { return price 200 } return super.discount(price) } }

再增加了国庆节支付类:

class NationalDayBill : Bill() { override fun discount(price: Double): Double { if (price < 100) { // 生成 0 ~ 9 随机数字,如果为 0 则免单。即:十分之一概率免单 val free = Random().nextInt(10) if (free == 0) { return 0.0 } } return super.discount(price) } }

「面向全国对象」让阿对最喜欢的一点是

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

有两个好消息要告诉大家!

当老板娘兴高采烈地说出这句话时

老过和阿对都露出了心惊胆战的表情

这句话往往意味着要更改需求

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

老过反抗道

但他并没有说出心里另两个小九九

实在不想再去给 Bill 类添加代码了

如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

这次修改老过花了较长的时间才完成

class Bill { val gifts = listOf(“flower”, “chocolate”, “9.9 discount”) fun getPrice(): Double { val unit = getUnit() val number = getNumber() val price = unit * number if (todayIsLoversDay() && isCouple()) { if (price > 99) { val lucky = Random().nextInt(gifts.size) println(“Congratulations on getting ${gifts[lucky]}!”) } return price * 0.77 } if (todayIsMiddleAutumn() && price > 399) { return price 200 } if (todayIsNationalDay() && price < 100) { // 生成 0 ~ 9 随机数字,如果为 0 则免单。即:十分之一概率免单 val free = Random().nextInt(10) if (free == 0) { return 0.0 } } return price } fun getUnit(): Double { } fun getNumber(): Int { } fun todayIsLoversDay(): Boolean { } private fun isCouple(): Boolean { } fun todayIsMiddleAutumn(): Boolean { } fun todayIsNationalDay(): Boolean { } }

看着那个只属于七夕节的 gifts 变量

老过像看着自己白衬衫上的油渍一样难受

以后每次收费时都会生成两个

只有七夕节才会用到的变量

都是因为老板娘的需求太奇葩

才让这个程序看起来乱糟糟的

由于这个类做了修改

本来已经测试通过的代码又得重测一遍

阿对打开了 LoversDayBill 类

将其修改如下

class LoversDayBill : Bill() { val gifts = listOf(“flower”, “chocolate”, “9.9 discount”) override fun discount(price: Double): Double { if (!isCouple()) return price if (price > 99) { val lucky = Random().nextInt(gifts.size) println(“Congratulations on getting ${gifts[lucky]}!”) } return price * 0.77 } fun isCouple(): Boolean { } }
如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?

当老板娘看完老过和阿对的代码后

再次兴奋地提出新需求时

老过顿时晕了过去……

赛事真是太焦灼了

最后赢得奖励的是?

第三个参赛者

老板娘的傻儿子

他完全不会写程序

但他使用 Ctrl+C,Ctrl+V

拷贝了阿对的代码

三、面试常见考点

在面试中,程序语言的常见考察点是三个基本特征:PCB、承继、多态。

PCB

PCB,也是把客观事物PCB成抽象化的类,并且类可以把自己的数据和方式只让可信的类或者对象操作,对不可信的展开信息隐藏。承继

承继是指这样一类能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对那些功能展开扩展。通过承继创建的新类称为「子类」或「派生类」,被承继的类称为「基类」、「父类」或「超类」。

要实现承继,可以通过 承继和组合 来实现。多态性

多态性是允许你将父对象设置成为和两个或更多的他的子对象相等的控制技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以相同的方式运作。简单说是一句话:允许将子类类型的指针赋值给父类类型的指针。

实现多态,有两种方式,覆盖和重载。两者的差别在于:覆盖在运行时下定决心,重载是在编译时下定决心。并且覆盖和重载的机制相同。例如在 Java 中,重载方式的签名必须有别于原先方式的,但对于覆盖签名必须相同。

我对程序语言的认知:程序语言的程式设计方式使得每两个类都只做一件事。面向全国操作过程会让两个类越来越全能,就像两个管家一样做了所有的事。而程序语言像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!

四、引申阅读

最后,我们谈谈程序语言有甚么好处?

大话设计模式》中大鸟给小菜讲的故事十分经典:

“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”

“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”

“样张再次出来请曹操过目,曹操细细一品,觉得却是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”

大鸟:“小菜你说,这里面问题出在哪里?”

小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”

大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余组织工作都未白做。岂不妙哉。

一、要改,只需更改要改之字,此为可维护;

二、那些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;

三、此诗若要加字,只需另刻字加入即可,这是可扩展;

四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”

“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”

小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一场控制技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是价值观的成功,程序语言的胜利。”

—————————-以下是原答案——————————-

与程序语言相对应的,即存在于早期版本 C 语言中的面向全国操作过程。

面向全国操作过程开发的操作过程,有点类似于树状调用函数,树状的根节点主程序对函数展开层层调用。

比如,main 函数要展开排序,那就调用 sort,sort 再去调用对应的,然后排好序后要展开输出,再调用输出。所谓面向全国操作过程中的操作过程,指的是排序,输出这两个个的对应的“行为”,即操作过程是你每次展开的操作。

面向全国操作过程的问题有:

复用性不佳

按操作过程来的话,相同操作过程中相似的代码也不好展开复用,前半段的操作过程中用到的逻辑,在后半段再次使用的话需要再写一遍,如果是相同的逻辑,修改也会出现很多复杂问题。

拓展性不易

举个例子,相同的逻辑,如果要有两份相似逻辑,那在面向全国操作过程中,就很多时候需要写两份。

耦合度高

有两个比喻很合适,说面向全国操作过程是蛋炒饭,程序语言是盖浇饭,即,面向全国操作过程很难将内容剥离开,都混在了一起,要改两个东西,往往会改全文;而程序语言改的时候就改得比较少。

但面向全国操作过程也有好处,迭代快速开发,在一些如 48 小时赛事写个程序的,快速迭代,按操作过程分割就比较适合面向全国操作过程。

程序语言,和面向全国操作过程的差别在于:

程序语言是以元素,是以事物为主体。只要你能将一样东西抽象化成一样物品,就可以作为你一段代码的载体。

比如,MVC,把一样东西的数据,页面,控制,各抽象化成两个东西,分开耦合,相同的对象之间只提供对应的接口,联系也基于对应的接口。把每个对象PCB成两个类,是程序语言要做的事情。

首先复用性极佳,你如果要编写重复逻辑,直接使用同两个类就好了。

其次耦合性十分低,修改逻辑时候只需要修改对应的接口内的内容就好了。

与此同时代码逻辑也更好认知,更好维护。

欢迎各位知友关注力扣官方微信公众号:「LeetCode力扣」,更多关于开发人员面试、控制技术干货的内容等你来啃!

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务