设计模式之美 - 面向对象
面向对象编程是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石 。
面向对象分析和设计
面向对象分析和设计两个阶段最终的产出是类的设计,包括程序被拆解为哪些类,每个类有哪些属性方法,类与类之间如何交互等等。它们比其他的分析和设计更加具体、更加落地、更加贴近编码,更能够顺利地过渡到面向对象编程环节。这也是面向对象分析和设计,与其他分析和设计最大的不同点。
面向对象分析就是要搞清楚做什么,面向对象设计就是要搞清楚怎么做,两个阶段最终的产出是类的设计,包括程序被拆解为哪些类,每个类有哪些属性方法、类与类之间如何交互等等。面向对象编程就是将分析和设计的的结果翻译成代码的过程。
封装、抽象、继承、多态分别可以解决的编程问题
封装
是什么?
封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。需要编程语言提供访问控制的语法
例子
因为从业务的角度来说,id、createTime 在创建钱包的时候就确定好了,之后不应该再被改动,所以,我们并没有在 Wallet 类中,暴露 id、createTime 这两个属性的任何修改方法,比如 set 方法。而且,这两个属性的初始化设置,对于 Wallet 类的调用者来说,也应该是透明的。
对于钱包余额 balance 这个属性,从业务的角度来说,只能增或者减,不会被重新设置
对于封装这个特性,我们需要编程语言本身提供一定的语法机制来支持。这个语法机制就是访问权限控制。
有什么用?
1,属性可以随意被以各种奇葩的方式修改,而且修改逻辑可能散落在代码中的各个角落,势必影响代码的可读性、可维护性。
2,除此之外,类仅仅通过有限的方法暴露必要的操作,也能提高类的易用性。如果我们把类属性都暴露给类的调用者,调用者想要正确地操作这些属性,就势必要对业务细节有足够的了解。而这对于调用者来说也是一种负担。相反,如果我们将属性封装起来,暴露少许的几个必要的方法给调用者使用,调用者就不需要了解太多背后的业务细节,用错的概率就减少很多。
抽象
是什么?
封装主要讲的是如何隐藏信息、保护数据,而抽象讲的是如何隐藏方法的具体实现,让调用者只需要关心方法提供了哪些功能,并不需要知道这些功能是如何实现的。(可以理解为:用一个函数实现一个功能,那么这个函数就是对这个功能的抽象)
常借助编程语言提供的接口类(比如 Java 中的 interface 关键字语法)或者抽象类(比如 Java 中的 abstract 关键字语法)这两种语法机制,来实现抽象这一特性。
实际上,实现抽象,并不一定要定义出 interface 然后实现它才算抽象。单纯的在类中通过函数包裹具体的实现逻辑,这本身就是一种抽象。因为类的方法是通过编程语言中的“函数”这一语法机制来实现的,调用者在使用函数的时候,并不需要去研究函数内部的实现逻辑,只需要通过函数的命名、注释或者文档,了解其提供了什么功能,就可以直接使用了。只需要提供“函数”这一非常基础的语法机制,就可以实现抽象特性、所以,它没有很强的“特异性”。
所以,抽象有时候会被排除在 OO 特性之外。
有什么用?
不需关心实现细节,降低复杂度,拿来即用
要有抽象思维,不要在方法定义中,暴露太多的实现细节,以保证在某个时间点需要改变方法的实现逻辑的时候,不用去修改其定义。如:getAliyunPictureUrl()->getPictureUrl()
继承
是什么?
继承是用来表示类之间的 is-a 关系
有什么用?
代码复用
从设计的角度来说,符合人类认知,一种结构美感。例子:猫类继承动物类。
小心基础层次过深,增加代码耦合度。
多态
是什么?
继承并重写父类方法或定义接口类并实现接口。
有什么用?
提高代码的可扩展性和复用性。多态也是很多设计模式、设计原则、编程技巧的代码实现基础,比如策略模式、基于接口而非实现编程、依赖倒置原则、里式替换原则、利用多态去掉冗长的 if-else 语句等等。
评论