封装、抽象、继承、多态
什么是 UML?我们是否需要 UML?
讲到面向对象分析、设计、编程,我们就不得不提到另外一个概念,那就是 UML(Unified Model Language),统一建模语言。很多讲解面向对象或设计模式的书籍,常用它来画图表达面向对象或设计模式的设计思路。
实际上,UML 是一种非常复杂的东西。它不仅仅包含我们常提到类图,还有用例图、顺序图、活动图、状态图、组件图等。在我看来,即便仅仅使用类图,学习成本也是很高的。就单说类之间的关系,UML 就定义了很多种,比如泛化、实现、关联、聚合、组合、依赖等。
要想完全掌握,并且熟练运用这些类之间的关系,来画 UML 类图,肯定要花很多的学习精力。而且,UML 作为一种沟通工具,即便你能完全按照 UML 规范来画类图,可对于不熟悉的人来说,看懂的成本也还是很高的。
所以,从我的开发经验来说,UML 在互联网公司的项目开发中,用处可能并不大。为了文档化软件设计或者方便讨论软件设计,大部分情况下,我们随手画个不那么规范的草图,能够达意,方便沟通就够了,而完全按照 UML 规范来将草图标准化,所付出的代价是不值得的。
所以,我这里特别说明一下,专栏中的很多类图我并没有完全遵守 UML 的规范标准。为了兼顾图的表达能力和你的学习成本,我对 UML 类图规范做了简化,并配上了详细的文字解释,力图让你一眼就能看懂,而非适得其反,让图加重你的学习成本。毕竟,我们的专栏并不是一个讲方法论的教程,专栏中的所有类图,本质是让你更清晰地理解设计。
当看到老师说uml意义不大的时候我就懵了,还好原来是指不需要按严格标准死磕uml。
我平时在功能开发初期和后期都是用uml把我的想法可视化然后让师兄审核,减少pr被reject机率。而且也容易让别的工程师接手做功能拓展。
不过确实互联网公司如果不是大厂,确实很少人能看懂uml。
作者回复: 实际上,大厂也未必都在用。比如类图中几种类关系,同学们有几个能准确的用不同的图线画出来呢?
封装(Encapsulation)
我们来看封装特性。封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。
public class Wallet {private String id;private long createTime;private BigDecimal balance;private long balanceLastModifiedTime;// ... 省略其他属性...public Wallet() {this.id = IdGenerator.getInstance().generate();this.createTime = System.currentTimeMillis();this.balance = BigDecimal.ZERO;this.balanceLastModifiedTime = System.currentTimeMillis();}// 注意:下面对 get 方法做了代码折叠,是为了减少代码所占文章的篇幅public String getId() { return this.id; }public long getCreateTime() { return this.createTime; }public BigDecimal getBalance() { return this.balance; }public long getBalanceLastModifiedTime() { return this.balanceLastModifiedTime;
把属性private,暴露get方法,对于封装这个特性,语法机制就是访问权限控制。例子中的 private、public 等关键字就是 Java 语言中的访问权限控制语法。private 关键字修饰的属性只能类本身访问,可以保护其不被类之外的代码直接访问。
类仅仅通过有限的方法暴露必要的操作,也能提高类的易用性。如果我们把类属性都暴露给类的调用者,调用者想要正确地操作这些属性,就势必要对业务细节有足够的了解。而这对于调用者来说也是一种负担。相反,如果我们将属性封装起来,暴露少许的几个必要的方法给调用者使用,调用者就不需要了解太多背后的业务细节,用错的概率就减少很多。这就好比,如果一个冰箱有很多按钮,你就要研究很长时间,还不一定能操作正确。相反,如果只有几个必要的按钮,比如开、停、调节温度,你一眼就能知道该如何来操作,而且操作出错的概率也会降低很多。
抽象
封装主要讲的是如何隐藏信息、保护数据,而抽象讲的是如何隐藏方法的具体实现,让调用者只需要关心方法提供了哪些功能,并不需要知道这些功能是如何实现的。
实际上,抽象这个特性是非常容易实现的,并不需要非得依靠接口类或者抽象类这些特殊语法机制来支持。换句话说,并不是说一定要为实现类(PictureStorage)抽象出接口类(IPictureStorage),才叫作抽象。即便不编写 IPictureStorage 接口类,单纯的 PictureStorage 类本身就满足抽象特性。
除此之外,抽象作为一个非常宽泛的设计思想,在代码设计中,起到非常重要的指导作用。很多设计原则都体现了抽象这种设计思想,比如基于接口而非实现编程、开闭原则(对扩展开放、对修改关闭)、代码解耦(降低代码的耦合性)等。我们在讲到后面的内容的时候,会具体来解释。
换一个角度来考虑,我们在定义(或者叫命名)类的方法的时候,也要有抽象思维,不要在方法定义中,暴露太多的实现细节,以保证在某个时间点需要改变方法的实现逻辑的时候,不用去修改其定义。举个简单例子,比如 getAliyunPictureUrl() 就不是一个具有抽象思维的命名,因为某一天如果我们不再把图片存储在阿里云上,而是存储在私有云上,那这个命名也要随之被修改。相反,如果我们定义一个比较抽象的函数,比如叫作 getPictureUrl(),那即便内部存储方式修改了,我们也不需要修改命名。
继承
从继承关系上来讲,继承可以分为两种模式,单继承和多继承。单继承表示一个子类只继承一个父类,多继承表示一个子类可以继承多个父类,比如猫既是哺乳动物,又是爬行动物。
Java 使用 extends 关键字来实现继承,C++ 使用冒号(class B : public A),Python 使用 paraentheses(),Ruby 使用 <。不过,有些编程语言只支持单继承,不支持多重继承,比如 Java、PHP、C#、Ruby 等,而有些编程语言既支持单重继承,也支持多重继承,比如 C++、Python、Perl 等。
继承最大的一个好处就是代码复用。假如两个类有一些相同的属性和方法,我们就可以将这些相同的部分,抽取到父类中,让两个子类继承父类。这样,两个子类就可以重用父类中的代码,避免代码重复写多遍。不过,这一点也并不是继承所独有的,我们也可以通过其他方式来解决这个代码复用的问题,比如利用组合关系而不是继承关系。
如果我们再上升一个思维层面,去思考继承这一特性,可以这么理解:我们代码中有一个猫类,有一个哺乳动物类。猫属于哺乳动物,从人类认知的角度上来说,是一种 is-a 关系。我们通过继承来关联两个类,反应真实世界中的这种关系,非常符合人类的认知,而且,从设计的角度来说,也有一种结构美感。
继承的概念很好理解,也很容易使用。不过,过度使用继承,继承层次过深过复杂,就会导致代码可读性、可维护性变差。为了了解一个类的功能,我们不仅需要查看这个类的代码,还需要按照继承关系一层一层地往上查看“父类、父类的父类……”的代码。还有,子类和父类高度耦合,修改父类的代码,会直接影响到子类。
所以,继承这个特性也是一个非常有争议的特性。很多人觉得继承是一种反模式。我们应该尽量少用,甚至不用。关于这个问题,在后面讲到“多用组合少用继承”这种设计思想的时候,我会非常详细地再讲解,这里暂时就不展开讲解了。
多态
多态是指,子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。对于多态这种特性,纯文字解释不好理解,我们还是看一个具体的例子。
对于多态特性的实现方式,除了利用“继承加方法重写”这种实现方式之外,我们还有其他两种比较常见的的实现方式,一个是利用接口类语法,另一个是利用 duck-typing 语法。不过,并不是每种编程语言都支持接口类或者 duck-typing 这两种语法机制,比如 C++ 就不支持接口类语法,而 duck-typing 只有一些动态语言才支持,比如 Python、JavaScript 等。'
重点回顾
今天的内容就讲完了,我们来一起总结回顾一下,你需要重点掌握的几个知识点。
1. 关于封装特性
封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。它需要编程语言提供权限访问控制语法来支持,例如 Java 中的 private、protected、public 关键字。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。
2. 关于抽象特性
封装主要讲如何隐藏信息、保护数据,那抽象就是讲如何隐藏方法的具体实现,让使用者只需要关心方法提供了哪些功能,不需要知道这些功能是如何实现的。抽象可以通过接口类或者抽象类来实现,但也并不需要特殊的语法机制来支持。抽象存在的意义,一方面是提高代码的可扩展性、维护性,修改实现不需要改变定义,减少代码的改动范围;另一方面,它也是处理复杂系统的有效手段,能有效地过滤掉不必要关注的信息。
3. 关于继承特性
继承是用来表示类之间的 is-a 关系,分为两种模式:单继承和多继承。单继承表示一个子类只继承一个父类,多继承表示一个子类可以继承多个父类。为了实现继承这个特性,编程语言需要提供特殊的语法机制来支持。继承主要是用来解决代码复用的问题。
4. 关于多态特性
多态是指子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。多态这种特性也需要编程语言提供特殊的语法机制来实现,比如继承、接口类、duck-typing。多态可以提高代码的扩展性和复用性,是很多设计模式、设计原则、编程技巧的代码实现基础。
Java 不支持多重继承的原因
多重继承有副作用:钻石问题(菱形继承)。
假设类 B 和类 C 继承自类 A,且都重写了类 A 中的同一个方法,而类 D 同时继承了类 B 和类 C,那么此时类 D 会继承 B、C 的方法,那对于 B、C 重写的 A 中的方法,类 D 会继承哪一个呢?这里就会产生歧义。
封装、抽象、继承、多态相关推荐
- java抽象 继承 多态 接口
**继承:**继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为 public class mp3 {private Str ...
- 整体理解抽象、封装、继承、多态
背景: 上一次我们比较形象化地介绍了类和对象.这一次简单介绍一下抽象封装和继承多态.这也是面向对象程序设计的重要特点,下面我们就一起来看看吧! 一.抽象 抽象是分析和设计中经常使用的一种重要的方法,也 ...
- 【Python从零到壹】面向对象的封装,继承和多态
面向对象的三大特征:封装,继承,多态 文章目录 1. 封装 2. 继承 多态的实现 封装: 提高程序的安全性 将数据(属性)和行为(方法)包装到类对象中,在方法内部对属性进行对象的外部调用方法. 这样 ...
- Java基础-OOP特性之封装、继承、多态、抽象
为什么80%的码农都做不了架构师?>>> //要习惯将程序(功能.代码)模块化 //OOP四大特性:封装.继承.多态.抽象 //OOP的核心:封装一个类,把数据抽象出来,再把方 ...
- java写一个外网访问的接口_【JAVA基础】一个案例搞懂类、对象、重载、封装、继承、多态、覆盖、抽象和接口概念及区别(中篇)...
0 前言 初学JAVA时,总会对一些概念一知半解,相互混淆,不明其设计的用意,如类.对象.重载.封装.继承.多态.覆盖.抽象类.接口概念.为便于理解和巩固,本文将基于一个案例及其变形,展现各个概念的定 ...
- 基础知识--封装、继承、多态、抽象
一.封装 封装:是面向对象方法的重要原则,就是把对象的属性和行为(数据)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节,就是把不想告诉或者不该告诉别人的东西隐藏起来,把可以告诉别人的公开,别人只 ...
- 对封装、继承、多态、抽象的理解
封装 封装是面向对象的重要原则,就是把对象的属性和行为(方法)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节.大白话讲就是,把不想告诉或者不该告诉别人的东西隐藏起来(private关键字修饰), ...
- 利用Java的特性(类的封装,类的继承,抽象,多态)编写一个银行系统对两种卡(借记卡、信用卡)进行管理。
文章目录 前言 一.关键技术 二.整体思路 三.运行界面 四.UML类图 总结 前言 模拟银行的系统,用户可以在银行填写相关基本信息,选择不同的银行卡类型开户(信用卡.借记卡),不同类型的卡在取款和消 ...
- Java继承_Hachi君浅聊Java三大特性之 封装 继承 多态
Hello,大家好~我是你们的Hachi君,一个来自某学院的资深java小白.最近利用暑假的时间,修得满腔java语言学习心得.今天小宇宙终于要爆发了,决定在知乎上来一场根本停不下来的Hachi君个人 ...
- 初步理解Java的三大特性——封装、继承和多态
声明:整理自网络,如有雷同,请联系博主处理 一.封装 封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被 ...
最新文章
- 数据分析之机器学习(整理笔记)
- oracle中有类似split的方法么,Oracle 实现拆分列数据的split()方法
- MS12_020漏洞
- linux top 命令的结果
- 云原生除了K8S、微服务,还有...?
- VS2010 C++ 插件 VissualAssistX 安装
- Java 开源企业信息化建设平台 O2OA 入选码云 GVP 项目
- 使Ruby自动定位查找本地路径
- taglib 标签文件
- ubuntu 14.04 android jdk,Ubuntu 14.04 安裝 jdk8u20 並配置環境變量 安裝Android Studio
- php jpgraph 中文,JPGraph 4.0(for PHP7)中文字体设置
- Python:批量转换图片格式
- 2019年保研夏令营复试经验分享(浙大软件/南大软件/南航计算机)
- pytorch之日志模板logging
- GB28181国标流媒体服务(LiveGBS)-支持海康8700等联网网关通过接入实现web端无插件直播
- ISO20022报文
- [Linux]history命令用法详解
- 解析2019年新零售社区团购发展方向
- 调试lan8720a遇到的奇葩问题,自动协商永远10M。
- Greedy Gift Givers