面向对象是什么?

2023-10-30

一、面向对象是什么面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。二、从一场比赛说起在一个软件村里有一名资深「面向过程」程序员——老过和一名「面向对象」信徒——阿对同时受雇于一家挨踢店有一天老板突发奇想决定让这两名程序员进行一次比赛获胜者将获得一个限量的 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 拷贝了阿对的代码三、面试常见考点在面试中,面向对象的常见考察点是三个基本特征:封装、继承、多态。封装封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。继承继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。要实现继承,可以通过 继承和组合 来实现。多态性多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!四、引申阅读最后,我们谈谈面向对象有什么好处?《大话设计模式》中大鸟给小菜讲的故事非常经典:“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”大鸟:“小菜你说,这里面问题出在哪里?”小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。一、要改,只需更改要改之字,此为可维护;二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;三、此诗若要加字,只需另刻字加入即可,这是可扩展;四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是思想的成功,面向对象的胜利。”----------------------------以下是原答案-------------------------------与面向对象相对应的,即存在于早期版本 C 语言中的面向过程。面向过程开发的过程,有点类似于树状调用函数,树状的根节点主程序对函数进行层层调用。比如,main 函数要进行排序,那就调用 sort,sort 再去调用对应的,然后排好序后要进行输出,再调用输出。所谓面向过程中的过程,指的就是排序,输出这一个个的对应的“行为”,即过程是你每次进行的操作。面向过程的问题有:复用性不佳按过程来的话,不同过程中相似的代码也不好进行复用,前半段的过程中用到的逻辑,在后半段再次使用的话需要再写一遍,如果是相同的逻辑,修改也会出现很多复杂问题。拓展性不易举个例子,相同的逻辑,如果要有两份相似逻辑,那在面向过程中,就很多时候需要写两份。耦合度高有一个比喻很合适,说面向过程是蛋炒饭,面向对象是盖浇饭,即,面向过程很难将内容剥离开,都混在了一起,要改一个东西,往往会改全文;而面向对象改的时候就改得比较少。但面向过程也有好处,迭代快速开发,在一些如 48 小时比赛写个程序的,快速迭代,按过程分割就比较适合面向过程。面向对象,和面向过程的区别在于:面向对象是以元素,是以事物为主体。只要你能将一样东西抽象成一样物品,就可以作为你一段代码的载体。比如,MVC,把一样东西的数据,页面,控制,各抽象成一个东西,分开耦合,不同的对象之间只提供对应的接口,联系也基于对应的接口。把每个对象封装成一个类,就是面向对象要做的事情。首先复用性极佳,你如果要编写重复逻辑,直接使用同一个类就好了。其次耦合性非常低,修改逻辑时候只需要修改对应的接口内的内容就好了。同时代码逻辑也更好理解,更好维护。作者:力扣(LeetCode)
链接:https://www.zhihu.com/question/27468564/answer/757537214
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一、面向对象是什么面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。二、从一场比赛说起在一个软件村里有一名资深「面向过程」程序员——老过和一名「面向对象」信徒——阿对同时受雇于一家挨踢店有一天老板突发奇想决定让这两名程序员进行一次比赛获胜者将获得一个限量的 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 拷贝了阿对的代码三、面试常见考点在面试中,面向对象的常见考察点是三个基本特征:封装、继承、多态。封装封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。继承继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。要实现继承,可以通过 继承和组合 来实现。多态性多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!四、引申阅读最后,我们谈谈面向对象有什么好处?《大话设计模式》中大鸟给小菜讲的故事非常经典:“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”大鸟:“小菜你说,这里面问题出在哪里?”小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。一、要改,只需更改要改之字,此为可维护;二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;三、此诗若要加字,只需另刻字加入即可,这是可扩展;四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是思想的成功,面向对象的胜利。”----------------------------以下是原答案-------------------------------与面向对象相对应的,即存在于早期版本 C 语言中的面向过程。面向过程开发的过程,有点类似于树状调用函数,树状的根节点主程序对函数进行层层调用。比如,main 函数要进行排序,那就调用 sort,sort 再去调用对应的,然后排好序后要进行输出,再调用输出。所谓面向过程中的过程,指的就是排序,输出这一个个的对应的“行为”,即过程是你每次进行的操作。面向过程的问题有:复用性不佳按过程来的话,不同过程中相似的代码也不好进行复用,前半段的过程中用到的逻辑,在后半段再次使用的话需要再写一遍,如果是相同的逻辑,修改也会出现很多复杂问题。拓展性不易举个例子,相同的逻辑,如果要有两份相似逻辑,那在面向过程中,就很多时候需要写两份。耦合度高有一个比喻很合适,说面向过程是蛋炒饭,面向对象是盖浇饭,即,面向过程很难将内容剥离开,都混在了一起,要改一个东西,往往会改全文;而面向对象改的时候就改得比较少。但面向过程也有好处,迭代快速开发,在一些如 48 小时比赛写个程序的,快速迭代,按过程分割就比较适合面向过程。面向对象,和面向过程的区别在于:面向对象是以元素,是以事物为主体。只要你能将一样东西抽象成一样物品,就可以作为你一段代码的载体。比如,MVC,把一样东西的数据,页面,控制,各抽象成一个东西,分开耦合,不同的对象之间只提供对应的接口,联系也基于对应的接口。把每个对象封装成一个类,就是面向对象要做的事情。首先复用性极佳,你如果要编写重复逻辑,直接使用同一个类就好了。其次耦合性非常低,修改逻辑时候只需要修改对应的接口内的内容就好了。同时代码逻辑也更好理解,更好维护。作者:力扣(LeetCode)
链接:https://www.zhihu.com/question/27468564/answer/757537214
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一、面向对象是什么面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。二、从一场比赛说起在一个软件村里有一名资深「面向过程」程序员——老过和一名「面向对象」信徒——阿对同时受雇于一家挨踢店有一天老板突发奇想决定让这两名程序员进行一次比赛获胜者将获得一个限量的 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 拷贝了阿对的代码三、面试常见考点在面试中,面向对象的常见考察点是三个基本特征:封装、继承、多态。封装封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。继承继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。要实现继承,可以通过 继承和组合 来实现。多态性多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!四、引申阅读最后,我们谈谈面向对象有什么好处?《大话设计模式》中大鸟给小菜讲的故事非常经典:“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”大鸟:“小菜你说,这里面问题出在哪里?”小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。一、要改,只需更改要改之字,此为可维护;二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;三、此诗若要加字,只需另刻字加入即可,这是可扩展;四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是思想的成功,面向对象的胜利。”----------------------------以下是原答案-------------------------------与面向对象相对应的,即存在于早期版本 C 语言中的面向过程。面向过程开发的过程,有点类似于树状调用函数,树状的根节点主程序对函数进行层层调用。比如,main 函数要进行排序,那就调用 sort,sort 再去调用对应的,然后排好序后要进行输出,再调用输出。所谓面向过程中的过程,指的就是排序,输出这一个个的对应的“行为”,即过程是你每次进行的操作。面向过程的问题有:复用性不佳按过程来的话,不同过程中相似的代码也不好进行复用,前半段的过程中用到的逻辑,在后半段再次使用的话需要再写一遍,如果是相同的逻辑,修改也会出现很多复杂问题。拓展性不易举个例子,相同的逻辑,如果要有两份相似逻辑,那在面向过程中,就很多时候需要写两份。耦合度高有一个比喻很合适,说面向过程是蛋炒饭,面向对象是盖浇饭,即,面向过程很难将内容剥离开,都混在了一起,要改一个东西,往往会改全文;而面向对象改的时候就改得比较少。但面向过程也有好处,迭代快速开发,在一些如 48 小时比赛写个程序的,快速迭代,按过程分割就比较适合面向过程。面向对象,和面向过程的区别在于:面向对象是以元素,是以事物为主体。只要你能将一样东西抽象成一样物品,就可以作为你一段代码的载体。比如,MVC,把一样东西的数据,页面,控制,各抽象成一个东西,分开耦合,不同的对象之间只提供对应的接口,联系也基于对应的接口。把每个对象封装成一个类,就是面向对象要做的事情。首先复用性极佳,你如果要编写重复逻辑,直接使用同一个类就好了。其次耦合性非常低,修改逻辑时候只需要修改对应的接口内的内容就好了。同时代码逻辑也更好理解,更好维护。作者:力扣(LeetCode)
链接:https://www.zhihu.com/question/27468564/answer/757537214
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一、面向对象是什么面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。二、从一场比赛说起在一个软件村里有一名资深「面向过程」程序员——老过和一名「面向对象」信徒——阿对同时受雇于一家挨踢店有一天老板突发奇想决定让这两名程序员进行一次比赛获胜者将获得一个限量的 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 拷贝了阿对的代码三、面试常见考点在面试中,面向对象的常见考察点是三个基本特征:封装、继承、多态。封装封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。继承继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。要实现继承,可以通过 继承和组合 来实现。多态性多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!四、引申阅读最后,我们谈谈面向对象有什么好处?《大话设计模式》中大鸟给小菜讲的故事非常经典:“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”大鸟:“小菜你说,这里面问题出在哪里?”小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。一、要改,只需更改要改之字,此为可维护;二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;三、此诗若要加字,只需另刻字加入即可,这是可扩展;四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是思想的成功,面向对象的胜利。”----------------------------以下是原答案-------------------------------与面向对象相对应的,即存在于早期版本 C 语言中的面向过程。面向过程开发的过程,有点类似于树状调用函数,树状的根节点主程序对函数进行层层调用。比如,main 函数要进行排序,那就调用 sort,sort 再去调用对应的,然后排好序后要进行输出,再调用输出。所谓面向过程中的过程,指的就是排序,输出这一个个的对应的“行为”,即过程是你每次进行的操作。面向过程的问题有:复用性不佳按过程来的话,不同过程中相似的代码也不好进行复用,前半段的过程中用到的逻辑,在后半段再次使用的话需要再写一遍,如果是相同的逻辑,修改也会出现很多复杂问题。拓展性不易举个例子,相同的逻辑,如果要有两份相似逻辑,那在面向过程中,就很多时候需要写两份。耦合度高有一个比喻很合适,说面向过程是蛋炒饭,面向对象是盖浇饭,即,面向过程很难将内容剥离开,都混在了一起,要改一个东西,往往会改全文;而面向对象改的时候就改得比较少。但面向过程也有好处,迭代快速开发,在一些如 48 小时比赛写个程序的,快速迭代,按过程分割就比较适合面向过程。面向对象,和面向过程的区别在于:面向对象是以元素,是以事物为主体。只要你能将一样东西抽象成一样物品,就可以作为你一段代码的载体。比如,MVC,把一样东西的数据,页面,控制,各抽象成一个东西,分开耦合,不同的对象之间只提供对应的接口,联系也基于对应的接口。把每个对象封装成一个类,就是面向对象要做的事情。首先复用性极佳,你如果要编写重复逻辑,直接使用同一个类就好了。其次耦合性非常低,修改逻辑时候只需要修改对应的接口内的内容就好了。同时代码逻辑也更好理解,更好维护。作者:力扣(LeetCode)
链接:https://www.zhihu.com/question/27468564/answer/757537214
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一、面向对象是什么面向对象 (Object Oriented,OO) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是 封装、继承、类。无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。二、从一场比赛说起在一个软件村里有一名资深「面向过程」程序员——老过和一名「面向对象」信徒——阿对同时受雇于一家挨踢店有一天老板突发奇想决定让这两名程序员进行一次比赛获胜者将获得一个限量的 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 拷贝了阿对的代码三、面试常见考点在面试中,面向对象的常见考察点是三个基本特征:封装、继承、多态。封装封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。继承继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。通过继承创建的新类称为「子类」或「派生类」,被继承的类称为「基类」、「父类」或「超类」。要实现继承,可以通过 继承和组合 来实现。多态性多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有两种方式,覆盖和重载。两者的区别在于:覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同。例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群职员,每个人做一件小事,各司其职,最终合作共赢!四、引申阅读最后,我们谈谈面向对象有什么好处?《大话设计模式》中大鸟给小菜讲的故事非常经典:“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’众文武齐呼:‘丞相好诗!’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”大鸟:“小菜你说,这里面问题出在哪里?”小菜:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”大鸟:“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。一、要改,只需更改要改之字,此为可维护;二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;三、此诗若要加字,只需另刻字加入即可,这是可扩展;四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。”“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”小菜:“是的,小时候我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷是思想的成功,面向对象的胜利。”----------------------------以下是原答案-------------------------------与面向对象相对应的,即存在于早期版本 C 语言中的面向过程。面向过程开发的过程,有点类似于树状调用函数,树状的根节点主程序对函数进行层层调用。比如,main 函数要进行排序,那就调用 sort,sort 再去调用对应的,然后排好序后要进行输出,再调用输出。所谓面向过程中的过程,指的就是排序,输出这一个个的对应的“行为”,即过程是你每次进行的操作。面向过程的问题有:复用性不佳按过程来的话,不同过程中相似的代码也不好进行复用,前半段的过程中用到的逻辑,在后半段再次使用的话需要再写一遍,如果是相同的逻辑,修改也会出现很多复杂问题。拓展性不易举个例子,相同的逻辑,如果要有两份相似逻辑,那在面向过程中,就很多时候需要写两份。耦合度高有一个比喻很合适,说面向过程是蛋炒饭,面向对象是盖浇饭,即,面向过程很难将内容剥离开,都混在了一起,要改一个东西,往往会改全文;而面向对象改的时候就改得比较少。但面向过程也有好处,迭代快速开发,在一些如 48 小时比赛写个程序的,快速迭代,按过程分割就比较适合面向过程。面向对象,和面向过程的区别在于:面向对象是以元素,是以事物为主体。只要你能将一样东西抽象成一样物品,就可以作为你一段代码的载体。比如,MVC,把一样东西的数据,页面,控制,各抽象成一个东西,分开耦合,不同的对象之间只提供对应的接口,联系也基于对应的接口。把每个对象封装成一个类,就是面向对象要做的事情。首先复用性极佳,你如果要编写重复逻辑,直接使用同一个类就好了。其次耦合性非常低,修改逻辑时候只需要修改对应的接口内的内容就好了。同时代码逻辑也更好理解,更好维护。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面向对象是什么? 的相关文章

  • java面向对象

    知识点总结 面向对象 1 instanceof 用来判断引用类型 2 Java中定义 类 的一个固定格式写法 修饰符 class 类名 零到多个构造器 零到多个成员变量 零道多个方法 零到多个初始化块 修饰符 public private
  • Python基础——面向对象

    面向过程适合思考小规模事情 面向对象适合思考大规模的事情 思维 xff1a 先判断事情是简单的 小规模的 xff0c 还是复杂 的 xff0c 大规模的 xff0c 然后选择不同的思维方式 遇到复杂问题 xff0c 先从问题中找名词 xff
  • Linux内核 面向对象 usb驱动,linux usb usbip驱动详解(四)

    我们先讲解vhci hcd驱动 linux 4 20 14的usbip驱动 usb主机控制器驱动hcd学习心得 xff1a 可以阅读某款SOC的主机控制器驱动代码 xff0c 譬如TI的am3358芯片 xff0c 可以看musb驱动代码
  • 【Java基础篇

    个人主页 兜里有颗棉花糖 欢迎 点赞 收藏 留言 加关注 本文由 兜里有颗棉花糖 原创 收录于专栏 JavaSE primary 本专栏旨在分享学习JavaSE的一点学习心得 欢迎大家在评论区讨论 目录 一 什么是多态 二 多态的实现条件
  • c++ oop构造函数与拷贝控制

    class Quote public Quote int x x x 如果我们删除的是一个指向派生类对象的基类指针 则需要虚析构函数 virtual Quote default 动态绑定析构函数 int x virtual void sho
  • Java基础(面向对象,继承,抽象类,接口,多态)

    文章目录 JAVA基础 面向对象 笔记整理 JAVA基础 面向对象 笔记整理 面向对象概述 1 面向对象的思想来源生活 2 任何的对象从两个方面描述 静态属性 动态属性 3 创建一个类 其实就创建了一个模板 4 创建了一个类就是创建了一个新
  • 趣解面向对象

    小白自述 过去就听说 到面向对象的时候即使没有女朋友 都可以new好多个 啥时候我也能想new多少new多少 面向对象听了很多老师的课 感觉好绕啊 这个类套那个类 怎么套的也是一头雾水 怎么才能学好了面向对象嘛 好多人都说面向对象是java
  • Java基础-面向对象

    Java基础 面向对象 由于年前工作太忙 实在没时间整理Java基本知识 但是可能长时间不更新不好看 再说我个人也没有半途而废的习惯 所以决定节前还是更新一篇吧 这也算是Java的基本思想和一些偏进阶的东西 如果思考透彻了 理解清楚了 那么
  • c++ opp虚函数和抽象基类

    class Base public Base default Base int x num x Base default virtual int getNum return num private int num class Derive
  • 面向对象-继承

    继承 概念 继承父类的属性和行为 使得子类对象可以直接具有与父类相同的属性 相同的行为 子类可以直接访问父类中的非私有的属性和行为 继承是多态的前提 如果没有继承 就没有多态 特点 java只能单继承 但可以多层继承 a继承b b继承c 那
  • 面向对象设计的SOLID原则

    S O L I D是面向对象设计和编程 OOD OOP 中几个重要编码原则 Programming Priciple 的首字母缩写 SRP The Single Responsibility Principle 单一责任原则 OCP The
  • 在JAVA中intValue()、parseInt()、valueOf()的区别

    JAVA API文档对于intValue parseInt valueOf 的介绍 详解见代码 package JAVA API public class Test public static void main String args I
  • 原来 Python 也有重载?

    Python作为一门动态语言 其实并不需要重载 但是如果你愿意的话 可以显式的声明重载 先简单介绍下什么是重载 Overload 重载 overloading 是在一个类里面 方法名字相同 而参数不同 返回类型可以相同也可以不同 提出问题
  • Java基础知识之笔记总结分享(超详细)

    给大家分享一篇我之前在学习java过程中的关于java基础部分的笔记 比较详细 内容也比较多 如有问题请指出以便修改 谢谢 篇幅较长建议收藏浏览 1 环境变量配置 JAVA HOME jdk路径 Path 要把jdk的bin目录路径 添加到
  • Java语言与面向对象的程序设计

    这几天很迷茫 听老师介绍了一款软件 中国大学MOOC 刚好我是软件专业的学生 索性听了北京大学老师的一节关于Java的讲课 果断被震撼到了 他们的讲课给人一种很深刻 深入 的感觉 我今天就把老师讲到的东西记了下来 以便于有兴趣的朋友阅读 J
  • JavaScript的OO思想(一)

    类class是Object Oriented面向对象的语言有一个标志 通过类我们可以创建任意多个具有相同属性和方法的对象 JavaScript中没有类的概念 但它也是面向对象的 只是实现方法会有所不同 创建单个对象有两种基本方法 1 使用O
  • Unity触控——单指、双指、Windows大屏多人触控

    前段时间做了个Windows系统的大屏触控程序 最多同时支持十点触控 并且在各自的小窗口中要分别处理 即每个小窗口中的触点为一个处理组 判断其单点或多点操作 按以往移动端程序的触屏事件Input GetTouch int index 不满足
  • 【Effective C++详细总结】第四章 设计与声明

    个人博客 https blog csdn net Newin2020 spm 1011 2415 3001 5343 专栏地址 C C 知识点 专栏定位 整理一下 C 相关的知识点 供大家学习参考 如果有收获的话 欢迎点赞 收藏 您的支持就
  • C# 实现一个简单的图书管理系统(无数据库)新手教程1

    源码在vs2005中测试可以运行 源码如下 using System class Card private string title author private int total public Card title author tot
  • 面向对象的单片机编程

    1 在看别人单片机程序时 你也许是奔溃的 因为全局变量满天飞 不知道哪个在哪用了 哪个表示什么 而且编写极其不规范 2 在自己写单片机程序时 也许你也是奔溃的 总感觉重新开启一个项目 之前的写过相似的代码也无法使用 得重新敲 代码重用度不高

随机推荐