前言:本文首先记录一下设计的六大原则,然后再逐一谈谈23种设计模式。
(PS:本文只做个人理解记录,有问题的地方欢迎各位指正补充)
设计的六大原则:
-
遵循单一职责原则
一个类只做一类事情。
举例: Person类就只管人的基本信息,需要给人加组织结构(PersonManager)的就不要在这个类里面杂糅。 -
开闭原则
开放拓展,封闭修改(需要进行新功能开发的时候,是以拓展的方式,而不是以修改原有代码的方式)。
抽象化设计,多态是开闭原则的关键。 -
里氏代换原则(LSP)
所有使用父类的地方,都可以用其子类替换。(使用该类的用户<客户端>并不会因为你替换了子类而感到烦恼) -
依赖倒置原则
依赖抽象,而不是依赖具体类。(面向抽象编程、面向接口编程) -
接口隔离原则(Interface Segregation Principle)
每一个接口都只负责自己的责任,别去做自己不该做的事。
例如:接口 Flyable 、Runable ,一个负责飞,一个负责跑。不能合二为一FlyRunable。
当实现类只想实现fly的时候,如果是实现FlyRunable,那么会有一个多余方法run不需要实现。
并且还有一个好处就是,作为第三方接口的时候,可以精确暴露最小量接口给客户。 -
迪米特法则(Law of Demeter)
不要和陌生人说话(不要和本类无关的对象有联系,降低耦合)
设计模式
1. Singleton单例模式
类只存在一个实例的时候使用。使用spring框架的时候,默认管理的bean就是单例。
以下介绍常见的几种单例实现方式(说明见图上):
这里讲一下“双重检查”为什么要加volatile关键字。
1.volatile保证线程间可见,当A线程初始化实例后,就会通知其他线程该变量的情况。
2.volatile禁止指令重排(有什么作用?详见下面解释):
首先了解一下对象创建的过程
- 1.在内存里申请一块空间
- 2.成员默认值 例如m=0 不是0就是null (半初始化状态)
- 3.成员赋值 例如m=8(初始化值)
- 4.建立连接(变量指向该地址)
在双重检查 instance = new DEMO3()的时候,会经过以上步骤(指令)。而JVM为了优化指令,提高程序运行效率,指令重排序可以在不影响单线程程序执行结果前提下进行。也就是说,以上1234四个步骤,可能执行顺序会发生变化。设想A线程在创建该单例实例的时候,正好创建对象顺序为1423,并且当该线程执行到14步骤的时候,B线程要使用该类的单例实例,那B拿到的会是什么?当然就拿到了一个没有初始化完全的对象。
2.Strategy策略模式
为了让程序有很好的延展性,策略模式把对象本身和运算规则区分开来。将规则分别封装起来,让它们之间可以互相替换,此模式让规则的变化,不会影响到使用该规则的用户。
例子:实现对不同动物的比较。
3.Adapter适配器
适配器即为接口转换器。
举一个生活中的例子,我国的额定电压是220V,美G的额定电压是110V。如果直接拿我们国家的冰箱去美G用,那是用不了的(不信的可以去拿一个电器去报废一下),这个时候需要用到“变压器”,也就是我们说的适配器。
再举一个我们JAVA上的例子
SqlServer 只能用ODBC,但是JAVA只能JDBC。如果我们要用JAVA去连接SqlServer,那么中间就需要有一个“适配器”驱动
JDBC-ODBC-BRIGDGE (JAVA-> JDBC -> JDBC-ODBC-BRIGDGE -> ODBC -> SQLSERVER)
4.桥接模式
- 双维度扩展
- 分离抽象与具体
- 用聚合方式(桥)链接抽象与具体
太抽象啦,看一下下面的案例吧!
5.Builder构建器
用于构建复杂对象。看实例就好了,主要是为了创建对象使用。