什么是面向对象编程思想?

一、面向对象是什么

面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。

面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。

二、从一场比赛说起

在一个软件村里,有一名资深「面向过程」程序人员(老过)和一名「面向对象」信徒(阿对)同时受雇于一家挨踢店有一天老板突发奇想决定让这两名程序员进行一次比赛获胜者将获得一个限量的 360 度全自动按摩椅编程比赛开始了:

image.png

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

class Bill{

// 获取总价
fun getPrice(): Double {
val unit = getUnit()
val number = getNumber()
val price = unit * number
return price
}

// 获取单价
fun getUnit(): Double {
        ...
}

// 获取数量
fun getNumber(): Int {
        ...
}
}

image.png

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

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 {
        ...
    }
}

image.png

他决定让新的收银方式继承 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
    }
}
image.png

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

坐在按摩椅上的舒服日子


image.png

听到新需求

老过一阵头大

不由在群里吐槽

image.png

吐槽归吐槽

老过在 getPrice 函数中

再次增加了条件判断

作者:力扣(LeetCode)
链接:https://www.zhihu.com/question/31021366/answer/761614647
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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)
    }
}

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


image.png

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

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

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

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


image.png

老过反抗道

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

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


image.png

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

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 {
        ...
    }
}
image.png

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

再次兴奋地提出新需求时

老过顿时晕了过去......

比赛真是太焦灼了

最后赢得奖励的是?

第三个参赛者

老板的傻儿子

他完全不会写程序

但他使用 Ctrl+C,Ctrl+V

拷贝了阿对的代码

3. 面试常见考点

在面试中,面向对象的常见考察点是三个基本特征:封装、继承、多态。

  • 封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
  • 继承 :继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。 要实现继承,可以通过 继承和组合 来实现。
  • 多态性 多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。 实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。

面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢。

面向对象的做法确实是把属性和功能封装起来,但是其核心是归类和抽象。

把相关的属性和功能集中起来,把可以分离的部分隔绝开来,从而把复杂的业务逻辑切割成互相之间可以相对独立的部分,降低开发的难度。

所以面向对象绝对不仅仅是弄一个class然后把一堆东西往里面塞,真正重要的是判断需要构造哪些class,它们之间的关联,以及把什么东西往哪一个里面塞。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,063评论 6 510
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,805评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,403评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,110评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,130评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,877评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,533评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,429评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,947评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,078评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,204评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,894评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,546评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,086评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,195评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,519评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,198评论 2 357

推荐阅读更多精彩内容