设计模式
参考文章:
设计模式七大原则
开闭原则
对扩展开放,对修改关闭。
程序需要扩展的时候,不是直接修改,而是扩展,从而实现一个热插拔的效果。
实现该效果,需要使用抽象类和接口。
单一职责原则
一个类只有一个引起它变化的原因。
里氏替换原则
使用基类的地方可以使用子类替换。
任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
里氏代换原则是对“开-闭”原则的补充。实现“开闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。
依赖倒置原则
面向接口编程。
迪米特法则
一个对象对另一个对象应该尽可能少的了解。
接口隔离原则
使用多个接口,比使用单个接口要好。
多个功能接口,比一个臃肿的完成所有任务的接口要更好使用。
合成复用用则
尽量使用对象组合,而不是继承来达到复用的目的。
常用的设计模式
1. 工厂模式
定义
抽象工厂模式会把不同产品子类进行分组,组内不同的产品子类对应同一个工厂子类的不同创建方法,这样就减少了工厂子类的创建
简单工厂模式 -> 工厂方法模式 -> 抽象工厂模式
简单工厂模式,可以通过工厂内部的代码,进行生成对象,实际上违背了开闭原则,类和工厂耦合严重。
工厂方法模式,应该多创建类,而不是在工厂里添加冗余的判断,去创建对象。
抽象工厂模式,一步步抽象分类,找到要生产对象的特征,进行解耦和组合,就可以得到。
异
- 工厂方法模式针对的是单个产品等级结构,而抽象工厂模式针对的是多个产品的等级结构
- 工厂方法模式每个具体的工厂只能创建一种产品对象,而抽象工厂模式的具体工厂能创建多个产品对象
同
- 工厂方法模式和抽象工厂模式的抽象产品都拥有多个具体地实现产品
- 工厂方法模式和抽象工厂模式的抽象工厂类都有多个具体地实现工厂类
2.策略模式
定义
定义一系列的算法,并可以实现自由的切换
具体实现,由用户决定。
3.状态模式
状态模式定义
对象内部状态的改变会改变其行为。
4.代理模式
代理模式主要是使用代理对象劫持原始对象,达到对原始对象的控制
代理模式分为:
- 静态代理
- 动态代理
静态代理
指的就是代理类里面注册了实现类,并且在代理类的方法里在用实现类方法时,插入了自己的方法,完成了对实现类的‘劫持’。
动态代理
jdk动态代理 -> 没有看懂为什么这么写,用到了java的反射
cglib动态代理
区别
可以看到 cglib 动态代理我们主要使用了 Enhancer 工具类以及实现了 MethodInterceptor 接口
Tips:如果被代理类对象实现了接口就使用 JDK 动态代理,否则使用 cglib 动态代理
5.单例模式
- 懒汉式
- 饿汉式
- 双重检查式
- 静态内部类式
- 枚举式
单例类会暴露一个公有静态方法,客户端需要调用这个静态方法获取到单例类的唯一对象。 在获取这个单例对象的过程中需要确保线程安全,即在多线程环境下构造单例类的对象也是有且只有一个,这也是单例模式实现中比较困难的地方。
懒汉式
调用会同步,造成内存损耗
饿汉式
不用也生成,增加内存消耗
双重检查式
多个操作,不是原子操作,高并发下jdk1.5之前会出现问题,执行操作的顺序无法保证。
后来官方具体化了volatile关键字,解决了一定的问题。
静态内部类式
第一次调用 getInstance 方法时才会去加载 Holder 并初始化 INSTANCE,这样既保证了线程的安全也保证了实例的唯一性。
枚举式
默认枚举的实例是线程安全的,并且在任何情况下都是单例,但是这种方式可读性不高。
6.建造者模式
建造者模式主要用来构建对象,将对象的构建与表示进行分离,它更加注重对象的构建过程。
7.原型模式
原型模式主要用于构建对象,通过拷贝原型对象来创建新的对象,拷贝方式主要分为两种:
- 浅拷贝
- 深拷贝
浅拷贝
拷贝一个对象时,如果对象里面的是基本类型,则拷贝的是基本类型的值。如果对象里面是引用类型,则拷贝的是引用类型的地址,此时并没有开辟新的内存空间。
深拷贝
拷贝一个对象时,如果对象里面的是基本类型,则拷贝的是基本类型的值,如果对象里面是引用类型,则将引用类型也拷贝一份,此时开辟了新的内存空间。
8.适配器模式
适配器模式主要用于适配另外一个不兼容的对象一起工作,主要分 3 种方式:
- 类适配
- 对象适配
- 接口适配
类适配
- 定义一个需要被适配的类
- 定义一个目标接口 现在我们需要在目标接口的 request 方法中调用 Adaptee 的 adaptee 方法,如何实现呢?
- 定义一个适配器的类继承要被适配的类和目标接口
对象适配
- 定义一个电压的接口
- 定义一个220V的实现类
- 适配器接口,outputDC5V 方法用于将输入的电压变为 5V 后输出
- 实现电源适配器
接口适配
在实际开发中,经常会遇到接口中定义了太多的方法,而有些方法我们是用不到的,此时我们就可以通过适配器模式适配接口
9.装饰者模式
看不懂的蛋炒饭
10.外观模式
外观模式主要用于简化系统的使用,它对外提供一个高层接口,并将子系统的功能进行封装
外观模式优点:
- 将对子系统的依赖转换为对外观类的依赖
- 对外部隐藏子系统的具体实现
- 增强了安全性
11.桥接模式
桥接模式主要用于抽象与实现之间的桥接,实现二者的解耦
例子:画圆形和长方形,并给他们涂上不同的颜色
桥接模式优点:
1、把事物和其具体实现分开,使得他们各自可以独立的变化
2、桥接接口作为你一个维度,抽象类作为一个维度,两者可以随意组合
12.组合模式
组合模式的特点就是把一组相似的对象,当作一个单一的对象
13.观察者模式
观察者模式主要用于当一个对象改变,其他对象能收到这种变化
搞了一段kotlin代码,看的迷糊了
14.模版方法模式
模版方法模式定义了一套算法框架,将一些步骤交由具体的子类去实现
模版方法模式主要有以下角色:
- 抽象类:定义了一套算法框架
- 具体实现类
15.责任链模式
日志的打点用到了这个责任链模式。
16.解释器模式
解释器模式就是定义一个解释器的规则去解释对象
一脸懵逼……
17.中介者模式
中介者模式主要是通过提供一个中介类来降低多个对象之间的通信复杂度
18.迭代器模式
迭代器模式主要用于顺序访问集合对象的元素,而不需要知道其底层表示
有点看源码的意思。
弹窗的顺序实现感觉是这个模式。
19.享元模式
享元模式主要用于减少创建对象的数量,减少内存占用,提高性能。
有点像java里面的集合set,还有redis里面的zset
20.访问者模式
访问者模式主要就是通过访问者类去访问对象元素并进行相关操作
21.命令模式
命令模式用于给不同的对象下达不同的命令
22.备忘录模式
备忘录模式主要用于保存对象的某个状态,以便在适当的时候恢复对象