设计原则是指导代码设计的一些经验总结,对于每一种设计模式都需要掌握它的设计初衷,能解决哪些编程问题,有哪些应用场景,这样才能在项目中灵活恰当地应用这些原则or 目前来看,能在阅读项目代码中对使用的设计模式有一个更清楚的认识
几个设计原则:
单一职责原则,开闭原则,里氏替换原则,接口隔离原则,依赖倒置原则,……
23种经典的设计模式可以分为三大类:创建型、结构性、行为型
面向对象
面向对象编程语言是支持类或对象的语法机制,并能实现面向对象编程四大特性(封装、抽象、继承、多态)的编程语言
封装
封装也叫做信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(函数)来访问内部信息或者数据,即public private protected
类仅仅通过有限的方法暴露必要的操作,也能提高类的易用性,调用者不需要了解太多背后的业务细节,且操作概率也会降低很多
抽象
封装主要讲隐藏信息、保护数据,而抽象讲的是如何隐藏方法的具体实现,让调用者只需要关心方法提供了哪些功能,并不需要知道这些功能是如何实现的
抽象这个概念是一个非常通用的设计思想,并不单单用在面向对象编程中,也可以用来指导架构设计等,而且这个特性也并不需要编程语言提供特殊的语法机制来支持, 只需要提供“函数”这一非常基础的语法机制,就可以实现抽象特性,所以“抽象”有时候并不看作面向对象编程的特性之一
抽象只关注功能点而不关注实现这一思路在代码实现中起到非常重要的作用,很多设计原则都体现了抽象这种设计思想,比如基于接口而非实现编程、开闭原则等
继承
is-a 最大的好处就是代码复用,如果两个类有一些相同的属性和方法,就可以讲这些相同的部分抽取到父类中,让两个子类继承父类,这样两个子类就可以重用父类中的代码,避免代码重复写很多遍。
不过过度继承会导致代码可读性、可维护性变差,因此要“多用组合少用继承”这种设计思想
多态
多态是指子类可以替换父类,在实际代码运行过程中,调用子类的方法实现,需要编程语言提供特殊的语法机制来实现。
1 编程语言要支持父类对象可以引用子类对象
2 要支持继承
3 要支持子类可以继承父类中的方法
多态特性能提高代码的可扩展性和复用性
面向对象和面向过程的区别
面向过程编程也是一种编程范式或编程风格,以过程(方法、函数、操作)作为组织代码的基本单元,以数据(成员变量、属性)与方法相分离为最主要的特点,通过拼接一组顺序执行的方法来操作数据完成一项功能。
不支持类和对象两个语法概念,不支持丰富的面向对象编程,仅支持面向过程编程;而面向对象风格的代码被组织成一组类,方法和数据结构被绑定在一起,定义在类中
由此:
- oop更加能应对大规模复杂程序的开发
对于大规模开发,整个程序处理流程错综复杂,并非只有一条主线;但面向对象是以类为思考对象,在进行面向对象编程的时候,并不是将复杂的流程拆解为一个一个方法,而是先思考如何给业务建模,如何将需求翻译为类,如何给类之间建立交互关系……当我们有了类的设计模式之后,再按照流程将类组装起来行程整个程序。 类也是面向非常好的组织函数和数据结构的方式,是一种将代码模块化的有效手段。按照功能的不同将函数和数据结构放到不同的文件里。 - oop风格的代码更易复用,易扩展,易维护
- oop语言更人性化、更高级、更智能
一些不妥:滥用全局变量和全局方法
在面向对象中,常见的全局变量有单例类对象、静态成员变量、常量等,常见的全局方法有静态方法;
单例类对象在全局代码中只有一份,所以它相当于一个全局变量。
静态成员变量归属于类上的数据,被所有实例化对象所共享,也相当于一定程度上的全局变量。
而常量是一种非常常见的全局变量,比如一些代码中的配置参数,一般都设置为常量,放在一个常量类中
静态方法一般用来操作静态变量或者外部数据,静态方法可以在不用创建对象的情况下,直接拿来使用,静态方法将方法与数据分离,破坏了封装特性,是典型的面向过程风格。
但,如果将程序中用到的所有的常量都放到一个常量类中,不是一个很好的设计思路
因为:
- 影响代码的可维护性
- 会增加代码的编译时间
当常量类中包含很多常量定义的时候,依赖这个类的代码就会很多。那每次修改常量类都会导致依赖它的类文件重新编译,因此会浪费很多不必要的编译时间 - 影响代码的复用性
如果在另一个项目中,复用本项目开发的某个类,而这个类又依赖这个常量类,即便这个类只依赖常量类中的一小部分常量,我们仍然需要把一整个常量类引入,这样就也引入了很多无关的常量到新的项目中
改进:
将常量类拆解为功能更加单一的多个类,比如MySQL配置相关的常量,就放到MySqlConstant类中
或者,更好的方法是并不单独设计Constant常量类,而是哪个类用到了某个常量,就将这个常量定义到这个类中
Utils类
utils类出现的问题背景:如果有两个类A和B,它们要用到一块相同的功能逻辑,为了避免代码重复,我们不应该在两个类中,将这个相同的功能逻辑,重复地实现两遍;虽然可以用到集成方法,将相同的属性和方法抽取出来,定义到父类中,子类复用父类的属性和方法,达到代码复用的目的,但有时候两个类不一定具有继承关系,因此也不能硬抽象出一个父类。
因此当不能用继承解决上述问题是,就可以定义一个新的类,不需要共享任何数据,即不需要定义任何属性, 即可以把它定义成只包含静态方法的Utils类。
定义数据和方法分离的类
也是一种面向对象编程中属于面向过程风格的代码。即数据定义咋一个类中,方法定义在另一个类中。MVC —> 基于贫血模型的开发模式
关于面向对象和面向过程的区别:
面向过程:顺序执行一系列操作,最后完成整个任务,是流程化的思维方式
面向对象:是一种自底向上的思考方式,它不是先去按照执行流程来分解任务,而是将任务翻译成一个一个的小的模块,也就是类,设计类之间的交互,最后按照流程将类组装起来,完成整个任务。