【总结记录】面向对象设计OOP三大特性(封装、继承、多态)、七大基本原则的理解(结合代码、现实实例理解)
文章目录
- 一. 三大特征的理解
- (1)封装
- (2)继承
- (3)多态
- (4)面向对象、面向过程的对比
- 二. 七大基本原则的理解
- (1)单一职责原则
- (2)开放封闭原则(OOP 核心)
- (3)里氏替换原则(OOP 标志)
- (4)依赖倒置原则
- (5)接口分离原则
- (6)迪米特原则(最少知识法则)
- (7)组合优先继承原则
拖了好久的总结= =。
对 OOP 的内容零散地看了一些,想了一些还是自己写一个总结来提升一下理解吧!
学好 OOP,也利于设计模式的学习~
一点自己的见解,疏漏错误的地方期待大佬在评论区指正~
文章定义、实例等参考了《大话设计模式》、什么是OOP、OOP七大原则等书籍、文章,感谢~
一. 三大特征的理解
(1)封装
定义:每个对象都包含它能进行操作所需要的所有信息。
好处:
- 减少耦合
- 类内部实现可以自由修改
- 类具有清晰的对外接口
例子:房子,用墙壁封装起来。
- 窗户、门口就是对外接口:设想一下,如果没有门窗(或者门窗是秘密暗道,不清晰),我们无法进入房子来使用里面的家具,那这个房子还有用吗?(清晰对外接口的必要性)
- 改变房间布局就是修改类内部:我的房子想怎么改就怎么改,不会给房外人带来困扰(自由修改内部的体现)
- 减少耦合:我想到的例子是合租;耦合度过高,相当于大家的房子都连在一起(没有墙壁封装),耦合度过高带来的问题,就是不必要的相互联系:比如我在家用着100寸电视打游戏,你家高三孩子无法避免地看到了,导致无心向学。而墙壁的封装就可以避免这个不必要的互相联系,也就是达到减小耦合度的效果。
图源网络,侵删
(2)继承
- 定义:子类可以理解为对父类的特殊化,除了具备父类特性外,还具备自己的独立个性。
- 子类拥有父类非 private 的属性和功能
- 子类具有自己的属性和功能(拓展)
- 子类可以用自己的方式实现父类的功能(重写)
- 好处:
- 提高代码复用率
- 易拓展
- 缺点:父类变,则子类不得不变——继承会破坏(1)的封装性。
可以看到(1)的好处2【自由修改】。显而易见,继承会威胁到这一效果:
父类的自由修改,可能会导致子类出现问题(比如新增抽象函数)。 - 这也显示着,继承是一种类与类之间强耦合的关系
因此,有一项“组合优先于继承”的原则,可以到下面的原则(7)再看一下~
- 例子:虽然大家应该都对继承熟悉了,不过这边还是写一个吧~
大凡是小凡的爹,因此小明和大明一样都是黄种人(父类特征)
虽然是大凡不会rap,但是小凡会(子类拓展)
大凡唱歌,唱高音;小凡唱歌,唱电音(方法重写)
大凡改变肤色,变成黑人,小凡也得变成黑人(破坏封装性,不能自由修改内部)联动一下计网,URI和URL也可以看成继承关系噢~(URL 是对 URI 的特殊化)
(3)多态
- 定义:不同对象执行相同动作,但要通过对象自己的代码执行。
- 子类以父类身份出现(对象声明必须是父类)
- 子类以自己方式实现(无论对象是否转换成父类,都用的继承链末端方法)
- 子类特有属性和方法不可使用
- 优点:提高了代码的维护性、拓展性
- 例子:这里直接用《大话设计模式》里的例子,这个讲的挺好的:
京剧艺术家大明,和子承父业的儿子小明。父亲表演当前生病了,小明代父表演:
小明穿大明的戏服,以大明的身份进行表演(父类身份)
小明还是以自己的理解进行表演(自己方式)
小明虽然说学了一手Breaking,但是父亲不会,所以不能使用(特有属性方法不可用) - 重载,算多态吗:按照上面的定义来看,应该不算。但是也有说算是静态多态的。总的来说应该是看具体定义,看成一种多态应该也是可以的。
(4)面向对象、面向过程的对比
各自相对优点:
- 面向过程:效率更高。(具体化、流程化,不用进行实例化过程)
- 面向对象:易维护、易复用、易扩展。(三大特性)
二. 七大基本原则的理解
诶,网上很多都是五大原则,为了全面点,我这边还是写七个的吧~
(1)单一职责原则
- 定义:一个类,应该有且只有一个引起它变化的原因
- 好处
- 耦合度低,变更引起的风险降低,提高可维护性。
- 类的职责明确,增加代码可读性。
- 例子:两种手机类,按照单一职责原则,手机应该只负责通话。
过多的功能,会提高类的复杂度,同时提高了耦合度。
(当然,显示中手机还是按照多种多样的来的,这里只是想表达一下)
class BadPhone {// 包括手电筒、相机、通话功能的手机类private int flashlightBrightness;private int cameraPixel;private int volume;public void flashlightFunctions() { }public void cameraFunctions() { }public void conversationFunctions() { }
}class GoodPhone {// 包括通话功能的手机类private int volume;public void conversationFunctions() { }
}
(2)开放封闭原则(OOP 核心)
- 定义:软件实体,应该是可以拓展,但是不可修改。
- 理解:一个类提供的外部可用接口,如果由于新的需求进行了修改,可能会导致依赖这个接口的其他方法瘫痪。解决方法就是通过拓展新接口,而非修改旧接口来实现新需求。
- 好处:可维护、可拓展、可服用、灵活性好(全包!)
- 例子:getID() 返回 String,printID() 依赖 getID()。现在多了一个返回 int 型 ID 的需求。
class MyClass2 {public String getID() {return "ID";}// Bad
// public int getID() {// return 123;
// }// Goodpublic int getIntID() {return 123;}public void printID() {// 如果修改 getID(),依赖 getID() 的 printID() 就会出错// 但是拓展 getIntID(),就没问题System.out.printf("%s", getID());}
}
(3)里氏替换原则(OOP 标志)
- 定义:子类型必须能够替换掉父类型。
- 优点:保证使用父类的模块在无需修改的情况下就能拓展,提升拓展性。
- 例子:举个开枪的例子吧~
class Gun {public void shoot() {System.out.println("fire!");}
}class GoodGun extends Gun {@Overridepublic void shoot() {System.out.println("fire! fire!");}
}class BadGun extends Gun {@Overridepublic void shoot() {System.out.println("sorry, I can't fire");}
}class Man {public void fire() {new Gun().shoot();// new GoodGun().shoot(); 可以替换,能开枪// new BadGun().shoot(); 不能替换,不能开枪}
}
(4)依赖倒置原则
- 定义:抽象不应该依赖细节,细节应该依赖于抽象。
- 理解:针对接口,而非实现进行编程。
- 例子:写一个项目A,用到 Redis(高层模块项目A,依赖于低层模块 Redis)。如今由于机子太烂,日常宕机,因此打算换成 etcd 来避免数据丢失的问题。
问题来了,由于项目A的代码绑定了 Redis,因此无法复用项目A的代码,这就问题很大~如何解决呢?如果项目A的代码依赖的不是Redis,而是抽象的 K-V 数据库,具有稳定的接口(也就是依赖于抽象),那就可以直接替换成 etcd 啦~
讲道理,我不会 Redis、etcd,这里的例子是大概举出来的,有误的话欢迎指出~
(5)接口分离原则
- 定义:客户端不应该依赖它不需要的接口。采用多个与特定客户类有关的接口,比采用一个通用的接口要好。
- 理解:相对于(1)单一职责原则(注重业务逻辑划分),这里要求的是接口的方法尽量少
- 好处:
- 避免接口污染
- 高内聚(一个软件模块是由相关性很强的代码),毕竟用多个合适接口啦~
- 灵活性
- 例子:实现老人机类,一个复杂的手机接口 VS 多个简单的功能接口
interface BadPhoneInterface {void fly();void swim();void watchTV();void buy();void talk();void sendMessage();
}// 老人机:只希望能打电话、发短信就好
// 非接口分离:采用了具有多个方法的接口,并非高聚合
class OldPhone1 implements BadPhoneInterface {@Overridepublic void fly() { }@Overridepublic void swim() { }@Overridepublic void watchTV() { }@Overridepublic void buy() { }@Overridepublic void talk() { }@Overridepublic void sendMessage() { }
}// 接口分离:高聚合,灵活,定制化~
interface Talker {void talk();
}interface MessageSender {void sendMessage();
}class OldPhone2 implements Talker, MessageSender {@Overridepublic void talk() { }@Overridepublic void sendMessage() { }
}
(6)迪米特原则(最少知识法则)
- 定义:如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法,可以通过第三者转发调用。
- 理解:根本思想是强调类之间的松耦合,促进了类的复用
- 例子:秋招时节~举一个求职例子吧!(当然,具体面试流程肯定没我瞎写的这么糙)
小红想进大厂A,于是花了大功夫认识了面试官1投简历,希望面试官1过几天能面她。
但是~还没来得及面,面试官1就跳槽了!那小红接下来该怎么办,继续花大时间来找面试官2、面试官3吗?这就是没有遵循迪米特原则了:
小红和(具体)面试官之间,不应该有直接的联系,这样耦合太高了。而应该是找HR!让HR来充当这个转发“求面试调用”的第三者,这样耦合度低,而且不会发生像上面那样的事情了^ ^
(7)组合优先继承原则
定义:能用组合的地方就不要继承,以保证封装性。
(6)(7)的代码有空再补了。。敲累了摆烂
花了一下午我是没想到的= =
希望这个总结能帮助读者有更多的OOP理解,感谢你能阅读到这里~
【总结记录】面向对象设计OOP三大特性(封装、继承、多态)、七大基本原则的理解(结合代码、现实实例理解)相关推荐
- Day55-每日一道Java面试题-Java 面向对象编程三大特性: 封装 继承 多态
Java 面向对象编程三大特性: 封装 继承 多态 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问.但是如果一个类没有 ...
- 深入理解Java面向对象三大特性 封装 继承 多态
1.封装 封装的定义: 首先是抽象,把事物抽象成一个类,其次才是封装,将事物拥有的属性和动作隐藏起来,只保留特定的方法与外界联系 为什么需要封装: 封装符合面向对象设计原则的第一条:单一性原则,一个类 ...
- Java面向对象三大特性(封装继承多态)解释及案例
文章目录 包 包基本语法 命名规则 命名规范 导入包实例 访问修饰符 面向对象编程-封装 面向对象编程-继承 super关键词 super和this的比较 方法重写/覆盖 (override) 注意事 ...
- python多态的三种表现形式_python小结----面向对象的三大特征(封装,继承,多态)
面向对象的三大特征: 封装,继承,多态 面向对象的编程思想核心:高类聚,低耦合–程序的设计模式范畴 封装 什么是封装: 在面向对象编程的思想中,对代码进行高度封装,封装又叫包装 封装就是指将数据或者函 ...
- Java 面向对象编程的三大特性——封装、继承、多态
一.类和对象 1. 首先,什么是对象呢? 对象简单的来说就是一个实物,比如一部 iPhone X 手机,它就是对象.它的屏幕.内存等就是它的属性. 手机能够打电话,发短信,这个功能就是它的方法. 2. ...
- 面向对象之:三大特性:继承(已讲),封装,多态
目录 1.封装 2.多态 3.类的约束 4. super()深入了解 前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个 ...
- 04 面向对象之:三大特性:继承,封装,多态
前言: Python面向对象的三大特性:继承,封装,多态 1.封装:把很多数据封装到一个对象中,把固定功能的代码封装到一个代码块,函数,对象,打包成模块.这都属于封装的思想.具体的情况具体分析,比如, ...
- Python面向对象之:三大特性:继承,封装,多态以及类的约束
前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情 ...
- 04 面向对象之:三大特性:继承(已讲),封装,多态。
前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情 ...
最新文章
- 市场营销部门OKR案例
- c# 可选参数与命名实参
- 全面开启线上参会报名!CNCC线上与现场参会者共赴技术盛宴!
- 对接钉钉审批_简信CRM分享:钉钉CRM应用
- LightOJ 1269 Consecutive Sum (Trie树)
- css--block formatting context
- 安卓系统双屏异显_Android实现双屏异显
- AY写给国人的教程- VS2017 Live Unit Testing[1/2]-C#人爱学不学-aaronyang技术分享
- javascript学习之闭包
- Java不满足的依赖异常_java – 新的缺失/不满足的依赖项WildFly 9中的错误
- Kubernetes详解(二十)——ReplicaSet控制器
- 后RCNN时代的物体检测及实例分割进展
- 面向生态合作伙伴的实践分享回顾
- 计算机基础应用课件,中职计算机应用基础课件
- 老子【道德经】全文翻译(全81章)
- Excel 对比两个表的相同列内容是否一致
- AM调制解调的Matlab和Simulink实现
- Python的Open CV学习三
- 服务器和交换机物理连接_「网络安全」网络设备篇(6)——四层交换机
- python编程练习--跑马灯
热门文章
- centos安装php服务器,在CentOS上安装搭建PHP+Apache+Mysql的服务器环境方法
- apache php 脚本,PHP脚本不在Apache服务器上执行
- c语言课程设计模块结构图,【图片】发几个C语言课程设计源代码(恭喜自己当上技术小吧主)【东华理工大学吧】_百度贴吧...
- java的字节码无法显示_【java】查看Java字节码文件内容的方法+使用javap找不到类 解决方法...
- python处理文件名_[请教]python的中文文件名处理
- mysql授予权限和撤销权限的关系_MySQL数据库常用的授予权限和撤销权限的命令讲解...
- 二隐层的神经网络实现MNIST数据集分类
- Halcon学习笔记:xyz_attrib_to_object_model_3d示例
- Python中class的简单介绍
- Python Twisted 介绍