面向过程与面向对象的区别 面向过程:(Procedure-Oriented Programming(面向过程程序设计),简记为POP),一种以过程为中心的编程思想。
面向对象:(Object Oriented Programming(面向对象程序设计),简记为OOP),将相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,是一种更贴近事物的自然运行模式。
思考:把大象装进冰箱需要几步? 面向过程:
步骤是:打开冰箱、把大象装进冰箱、关闭冰箱
编码实现:open()、put()、close()
面向对象:
对象:大象、冰箱
编码实现:elephant、fridge
对象的行为:大象进冰箱、冰箱打开、冰箱关闭
再以实际情况调整对象行为的顺序:冰箱打开、大象进冰箱、冰箱关闭
编码实现:fridge.open()、elephant.put()、fridge.close()
总结: 面向过程:把问题分解为若干个步骤,每个步骤实现为一个函数,按照顺序实现并在调用时传递数据给函数解答问题。 面向对象: 抽象出问题的各种对象,把对象的属性和解决问题的方法封装在对象中,而后各个对象之间通过行为实现解答问题。 概念补充: 对象:现实世界中存在的任意一个可以被明确标识的实体。例如上述例子中所讲述的:一个冰箱,一只大象等。
类:具有同种属性的对象称为类,是个抽象的概念。比如“人”就是一类,其中包括小明、小红、小玲等等这些都是对象,类就相当于一个模具,他定义了它所包含的全体对象的公共特征和功能,对象就是类的一个实例化,小明就是人的一个实例化!我们在做程序的时候,经常要将一个变量实例化,就是这个原理!我们一般在做程序的时候一般都不用类名的,比如我们在叫小明的时候,不会喊“人,你干嘛呢!”而是说的是“小明,你在干嘛呢!”
类的成员主要包括:属性、方法和构造方法
属性:对象静态的一面,如:大象的重量,形状等都是描述大象的属性
方法:对象动态的一面,如:大象进冰箱,冰箱的关闭和打开
构造方法:构造方法是一种特殊的方法,专用于构造该类的实例(如实例的初始化、分配实例内存空间等),Java语言通过new关键字来调用构造方法,从而返回该类的实例。构造方法的格式: 权限修饰符 函数名(参数列表){ 函数体; }
面向过程与面向对象的优势与弊端 看了很多文章,发现了一篇将面向过程和面向对象比喻的十分淋漓尽致地文章,分享给大家~
用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。所谓盖浇饭,北京叫盖饭,东北叫烩饭,广东叫碟头饭,就是在一碗白米饭上面浇上一份盖菜,你喜欢什么菜,你就浇上什么菜。我觉得这个比喻还是比较贴切的。
蛋炒饭制作的细节,我不太清楚,因为我没当过厨师,也不会做饭,但最后的一道工序肯定是把米饭和鸡蛋混在一起炒匀。盖浇饭呢,则是把米饭和盖菜分别做好,你如果要一份红烧肉盖饭呢,就给你浇一份红烧肉;如果要一份青椒土豆盖浇饭,就给浇一份青椒土豆丝。
蛋炒饭的好处就是入味均匀,吃起来香。如果恰巧你不爱吃鸡蛋,只爱吃青菜的话,那么唯一的办法就是全部倒掉,重新做一份青菜炒饭了。盖浇饭就没这么多麻烦,你只需要把上面的盖菜拨掉,更换一份盖菜就可以了。盖浇饭的缺点是入味不均,可能没有蛋炒饭那么香。
到底是蛋炒饭好还是盖浇饭好呢?其实这类问题都很难回答,非要比个上下高低的话,就必须设定一个场景,否则只能说是各有所长。如果大家都不是美食家,没那么多讲究,那么从饭馆角度来讲的话,做盖浇饭显然比蛋炒饭更有优势,他可以组合出来任意多的组合,而且不会浪费。
盖浇饭的好处就是”菜”“饭”分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是”可维护性“比较好,”饭” 和”菜”的耦合度比较低。蛋炒饭将”蛋”“饭”搅和在一起,想换”蛋”“饭”中任何一种都很困难,耦合度很高,以至于”可维护性”比较差。软件工程追求的目标之一就是可维护性,可维护性主要表现在3个方面:可理解性、可测试性和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。
接下来,我将进行相应的总结,希望对你们有帮助。
面向过程 优势:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
弊端:没有面向对象易维护、易复用、易扩展
面向对象 优势:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
弊端:性能比面向过程低 原文链接:https://blog.csdn.net/MillionSong/article/details/104595623
1.
面向对象是相对于面向过程的,比如你要充话费,你会想,可以下个支付宝,然后绑定银行卡,然后在淘宝上买卡,自己冲,这种种过程。但是对于你女朋友就不一样了,她是面向“对象”的,她会想,谁会充话费呢?当然是你了,她就给你电话,然后你把之前的做了一遍,然后她收到到帐的短信,说了句,亲爱的。这就是面向对象!女的思维大部分是面向“对象”的!她不关心处理的细节,只关心谁可以,和结果!
继承,就是你俩生了个儿子,你把你充话费这套教给孩子,孩子学会后可能用不一样的流程,但是都能充。你“对象”可以喊你孩子充话费。 多态,就是还有个男的,叫“老王”,你“对象”想充话费,无所谓找你或者老王,都可以说“亲爱的,帮我充话费”。
在这个例子中,“我”这个对象不仍然是要设计吗?也就是说,仍然需要对“我”的功能什么的重新进行一个定义编写,那么这两者之间的区别也就只是换了个做这件事的人罢了,其意义何在呢?
意义在于,一旦“我”熟练的完成“充话费”这个行为之后,任何人都可以使用“我”来充话费了,不单单是现任女朋友,也可以是老妈,也可以是同事朋友。
你现在只要打开app就能点到外卖,不用自己去买菜做饭烧水,等于一天省了几个小时做饭,这就是意义嘛
2.
面向对象是相对面向过程说的。
简单来说,区别就是一个是make a dog bark,一个是a dog barks:
makebark(dog)
dog.bark()
----------------------------------
面向对象的做法确实是把属性和功能封装起来,但是其核心是归类和抽象。
把相关的属性和功能集中起来,把可以分离的部分隔绝开来,从而把复杂的业务逻辑切割成互相之间可以相对独立的部分,降低开发的难度。
所以面向对象绝对不仅仅是弄一个class然后把一堆东西往里面塞,真正重要的是判断需要构造哪些class,它们之间的关联,以及把什么东西往哪一个里面塞。
3.
谈谈面向对象有什么好处?
《大话设计模式》中大鸟给小菜讲的故事非常经典:
“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”
“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”
“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”
大鸟:“小菜你说,这里面问题出在哪里?”
小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”
大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。
一、要改,只需更改要改之字,此为可维护;
二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;
三、此诗若要加字,只需另刻字加入即可,这是可扩展;
四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”
“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”
小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是思想的成功,面向对象的胜利。”
4.
在一个软件村里
有一名资深「面向过程」程序员——老过
和一名「面向对象」信徒——阿对
同时受雇于一家挨踢店
有一天老板突发奇想
决定让这两名程序员进行一次比赛
获胜者将获得一个限量的
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
拷贝了阿对的代码
总结: 面向对象是什么面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。
无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。
面向对象的常见考察点是三个基本特征:封装、继承、多态。
- 封装 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
- 继承 继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。 要实现继承,可以通过 继承和组合 来实现。
- 多态性 多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。 实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。
我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!
链接:https://www.zhihu.com/question/31021366/answer/761614647
当然, 没有什么是完美的。 链接:https://www.zhihu.com/question/29888990/answer/704512665
oo分流派的,现在通常说的oo是指java/c++这一派,搞类、搞继承、搞多态。古典oo是erlang这一派的,每个对象object是个actor,对象间通过消息通讯,没有继承这一说,对象间不共享状态。Joe看不起现代派oo。erlang自己是古典派的,如何看的起现代派。
至于c++标志性的template,不属于oop的概念。
Alan Kay,oop概念发明者,也是图灵奖获得者,说了:
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. OOP对我来说,就是指消息、本地记忆与保护、隐藏状态与进程、所有事物的极端延迟绑定。可以在Smalltalk也可以在LISP实现。据我所知,殿堂级大师,都看不上以Java/c++为代表的现代派oop。
古典派OO的对象,说白了,就是自己管理自己一切、跟其他人只通过消息通信的“东西”。Erlang是古典oo在工业界得到应用的最成功的语言,由爱立信首创,在电信领域得到广泛应用。由于actor模型的每个对象(Erlang叫process,跟通常理解的process不同,非常轻,典型erlang应用,可能有百万个process在跑着)之间隔离,只通过“消息”通信,一个actor死了,其他的照样继续工作。
由于每个actor间隔离,可以跑在不同线程、进程、物理机器上,不用担心烦人的多线程的状态竞争问题,再加上Erlang有process的监控、重启的机制,导致用Erlang的分布式系统,可靠性及其之高,十分适合电信行业。
进入互联网时代后,Erlang这种基于actor的分布式计算,简直就是为微服务、分布式计算而生的。Scala就搞了个akka,Erlang也衍生出了Elixir。
现代OO,有Java/C++这样流行的语言,应用广泛,肯定由他的明显的优点,不多说了。就我自己来说,个人偏好,比较喜欢函数式编程,工作中现代oo主要用来做模块分割,仅此而已。