面向对象与封装、抽象、继承、多态

面向对象

现如今大部分程序员都在使用面向对象编程语言,进行面向对象开发。本文就来谈谈面向对象编程及其4大特性(封装、抽象、继承、多态)

什么是面向对象编程与面向对象编程语言

面向对象编程(OOP,Object Oriented Programming),是一种编程范式,以类和对象作为代码组织的基本单元,将封装、抽象、继承、多态作为代码设计与实现的方法论。
面向对象编程语言(OOPL,Object Oriented Programming Language),是一种能够提供语法机制以支持类与对象的编程语言,并能够提供语法机制,以方便的实现封装、抽象、继承、多态4大特性。
面向对象编程中有两个非常重要、非常基础的概念,那就是类(class)和对象(object)。这两个概念最早出现在1960年,在Simula这种编程语言中第一次使用。而面向对象编程这个概念第一次被使用是在Smalltalk这种编程语言中。Smalltalk被认为是第一个真正意义上的面向对象编程语言。
1980年C++的出现,带动了面向对象编程的流行,也使得面向对象编程被越来越多的人认可。直到今天,如果不按照严格的定义来说,大部分编程语言都是面向对象编程语言,比如 Java、C++、Go、Python、C#等等。
注意“不按照严格的定义”这几个字,实际上面向对象编程最最重要的就是类与对象,编程语言只要提供了类与对象的语法机制,就可以说是一种面向对象编程语言。但是在前人在编程过程中,发现通过封装、抽象、继承、多态这4大特性,可以更方便的实现各种各样的面向对象设计模式,设计出可维护、可扩展、可读性的代码。

什么是面向对象分析与面向对象设计

面向对象分析(OOA Object Oriented Analysis)、面向对象设计(Object Oriented Design)与面向对象编程,实际上就是面向对象编程的三个阶段:分析、设计与实现(编程)。面向对象的分析与设计是围绕着类与对象进行的,其产出是将系统分为了哪些类,每个类都有哪些方法与属性,类与类之间是什么关系等等。

总之,面向对象分析就是要搞清楚做什么,面向对象设计就是要搞清楚怎么做,面向对象编程就是将分析和设计的的结果翻译成代码的过程。

面向对象编程4大特性

封装(Encapsulation)

封装也叫信息隐藏或者数据保护,外部代码只能通过类暴露的少量的接口(方法或者函数),访问类的信息与数据。编程语言需要提供一种访问权限控制的语法,如C++的public、private、protected,使得外部只能访问部分接口,从而隐藏类实现的细节,保护数据。
如果我们对类的属性与所有方法都不做权限控制,所有的属性与方法,任何代码都可以使用。虽然这样提供了更好的灵活性,但是过度的灵活意味着不可控,不可控意味着较差的可维护性与可读性。想想任何代码都可以访问与修改类的属性,可以访问类的任何方法,那么类的属性与方法将散落到各处,如果我们哪天需要修改类的实现细节,那么需要修改非常多的代码,代码的可读性与可维护性很差。而且类的掉用者还需要了解类的实现细节,每个属性与方法的作用。想想是多么可拍。
封装可以使得我们的类更易维护,更可读,更易使用。

抽象(Abstraction)

抽象讲的是如何隐藏方法的实现细节,让调用者只需关心方法提供了哪些功能。面向对象编程中通常通过接口类或者抽象类语法机制来实现。实际上,抽象并不一定需要通过接口类或者抽象类来实现,也就是说我们可以不需要为每个类都定义一个接口或者抽象类。因为函数本身就是对实现细节的抽象。调用者在使用函数的时候,本身就不需要关心函数的实现细节,只需要查看函数名、参数列表、注释或者文档即可。为此函数的命名,变量的命名(报考函数参数),注释与文档是十分重要的,因为调用者需要通过这些信息知晓函数有哪些功能,应该怎么使用。
抽象这个特性也并不需要编程语言提供特殊的语法机制来支持,只需要提供“函数”这一非常基础的语法机制,就可以实现抽象特性、所以,它没有很强的“特异性”,有时候并不被看作面向对象编程的特性之一。
实际上,如果上升一个思考层面的话,抽象及其前面讲到的封装都是人类处理复杂性的有效手段。在面对复杂系统的时候,人脑能承受的信息复杂程度是有限的,所以我们必须忽略掉一些非关键性的实现细节。而抽象作为一种只关注功能点不关注实现的设计思路,正好帮我们的大脑过滤掉许多非必要的信息。
除此之外,抽象作为一个非常宽泛的设计思想,在代码设计中,起到非常重要的指导作用。很多设计原则都体现了抽象这种设计思想,比如基于接口而非实现编程、开闭原则(对扩展开放、对修改关闭)、代码解耦(降低代码的耦合性)等。
换一个角度来考虑,我们在定义(或者叫命名)类的方法的时候,也要有抽象思维,不要在方法定义中,暴露太多的实现细节,以保证在某个时间点需要改变方法的实现逻辑的时候,不用去修改其定义。比如 get_aliyun_picture_url() 就不是一个具有抽象思维的命名,因为暴露了过多的实现细节,如果某一天如果我们不再把图片存储在阿里云上,而是存储在私有云上,那这个命名也要随之被修改。相反,如果我们定义一个比较抽象的函数,比如叫作 get_picture_url(),那即便内部存储方式修改了,我们也不需要修改命名。

继承(Inheritance)

继承用于表示一种is-a的关系,例如狗是一种哺乳动物。继承又可以分为单继承与多重继承,有些语言只支持单继承如java,有些语言既支持单继承又支持多继承如C++。但是支持多继承往往存在钻石问题。不同的编程语言会使用不同的语法机制用于实现继承,如C++使用”:”号。
继承最大的一个用处就是用于实现代码复用,例如两个类A与B有很多公共的代码实现逻辑,那么我们可以使用一个公共的父类C将公共的实现逻辑放到C中,让A与B分别继承自C。
但是如果继承的层次过深或者继承关系过于复杂,也会导致代码的可读性与可维护性变差,我们使用一个类的时候,不仅需要了解这个类本身,还要了解这个类的父类,已及父类的父类,以此类推。还有子类与父类高度耦合,修改父类的代码实现,子类也会受影响。
为此很多人觉得继承是一种反人类的设计,很多面向对象的编程语言就不支持继承,如go。如果类的继承关系过于复杂,我们应该使用组合而不是继承用于实现代码的复用。

多态(Polymorphism)

多态指的是子类可以重写父类的方法,通过父类的指针或者引用,可以调用子类的方法。在静态编程语言中,多态往往是通过继承父类或者接口类来实现,需要提供如下的语法机制
A.子类可以重写父类的方法
B.需要支持继承
C.父类对象可以引用子类的对象,通过父类对象的引用调用,可以调用子类重写的方法。
多态最大的用途是用于实现代码复用与代码的可扩展性。也是很多设计模式、设计原则、编程技巧的实现基础,比如策略模式、基于接口而非实现编程、依赖倒置原则、里式替换原则、利用多态去掉冗长的 if-else 语句等等

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值