10.19 设计模式
其实通读完了设计模式,学到的一点是要对谁拿到谁的引用要明白,又隐藏另一个引用的什么东西呢?
1 备忘录模式
速记:后悔药:保存对象的临时状态,以便在需要的时候恢复对象
应用: 游戏存档,ctrl+z,IE中的后退
实现
- state存储类,提供getter查询锁包含的 state 状态
- 管理state类,维护一个的栈来管理 state类
- 使用者,产生状态,可以调用 sava保存自己状态,get方法获得以前保存的状态
2 观察者模式
速记:一个对象变化,同时所有观察他的人
应用:Vue的js中的watcher
实现
- 各种 observe 里面有个 update方法
- 被观察者有个notifyAll方法,当被观察者的state发生改变的时候,会notifyAll所有它attach的观察者
3 状态模式
速记:依据上下文来决定动作
应用:状态管理,比如电梯的状态,打篮球的时候运动员可以有正常状态、不正常状态和超常状态。常规的做法是 final 每个状态变量,然后switch case 对每个 final 采取的相应动作
实现
- 上下文(contex)持有一个抽象状态变量 state
- 具体的state在采取action时会将contex中的state设置为自己
4 策略模式
速记:Context主动选择已定义的不同策略
应用:诸葛亮的锦囊妙计
实现:
- context持有一个stragy变量
- context可以new出来不同的策略
和状态模式差不多,但是区别在于,策略模式是context主动选择策略而采取相应的行为,而状态模式则是被动状态改变导致context行为改变
5 空对象模式
略
6 模板模式
略
7 访问者模式
速记:访问者去帮助类实现某些东西
应用:不改变对象结构,增加新的功能
实现:
- 实体的每个零件中 accept 方法接受访问者访问,
- 访问者通过visit重载方法去访问每个零件
8 MVC 模式
略
9 业务代表模式
速记:客户要办事,就交给业务代表去办
应用:
实现:
- 抽象服务接口,子类实现不同服务。
- 查询服务向上提供接口给业务代表查,向下调用抽象服务接口
- 业务代表通过查询服务lookup拿到服务
- 客户和业务代表交互
10 组合实体模式
速记:大类包小类
应用:bean持久化存储到数据库,用复合bean去操作小bean
实现:
- 小bean
- 复合bean
11 数据访问对象模式(DAO模式)
速记:通过 api 操作数据对象
应用:spring service 的增删查改接口 来操作 pojo
实现:
- Dao 的 crud 接口,DaoImpl
- pojo
12 前端控制器模式
速记:一个 service 负责集中接受所有请求,然后负责分发下去,handler处理后返回 response
应用:springMvc的前端控制器,对 url request 进行解析,分发给对应的 controller,返回response
实现:
- FrontController 类接受所有请求,调用dispatch分发下去
- 具体的handler收到后处理请求,返回response
13 拦截过滤器模式
速记:一个过滤器链条来对权限日志进行管理,预处理或者后处理拦截
应用:springMvc的拦截器
实现:
- 各种拦截过滤器,比如日志拦截器,权限拦截器
- 对request执行的handler
- 对request执行的handler过滤器链中可以增加一系列拦截,然后启动handler
- 过滤器的管理,负责对过滤器链中的过滤器进行增加和删除,然后将request分发到过滤器链中
14 过滤器模式(filter模式,标准模式)
速记:结合多个标准来获得单一标准,对不符合标准的东西进行过滤
应用:springMvc制定了标准过滤
实现:
- 通过一个抽象接口来调用多个不同的标准
15 传输对象模式
速记:服务端从数据库种取数据,填充 pojo 类,然后将 pojo 对象通过网络序列化传输
应用:springMvc 的 json返回
实现:
- pojo,dao,数据库
16 服务定位器模式
速记:建立缓存。第一次通过JNDI查询数据库,第二次查询缓存。
应用:JNDI缓存cache查询
实现:
- JNDI initContext根据名字创建类(工厂模式)
- Cache类,对传输进来的对象进行缓存(传输对象模式)
- serviceLocator 类,声明一个静态 cache,先查找缓存有没有,没有则新建,然后进入缓存
17 工厂模式
简单工厂模式
速记:交给工厂取 new 对象,调用者只需要知道名字即可
应用:spring的java bean;一类手机产品
实现:
- 工厂类 return new xx();
工厂模式(抽象工厂的单产品族)
速记:不同类型的工厂继承工厂,new工厂的时候就决定了产品类型
应用:
实现:
- 工厂模板类
- 具体工厂类
- 工厂下的产品
抽象工厂模式
速记:抽象工厂生产工厂,并且定义工厂所生产的产品
应用:一套pc,键盘,鼠标等来自一个工厂
实现:
- 一个抽象工厂,定义了要生产的产品
- 具体的工厂生产自己类型的产品
- 具体的产品
18 单例模式
饿汉式
饿汉饿在不管要不要new对象,都给你一个new对象。就像不管一个人想不想吃东西都把吃的先买好,如同饿怕了一样
- 线程安全
速记与实现:利用类加载时就static,来直接 new 对象
懒汉式
懒汉懒在调用实例化方法时才new对象,类加载时没有new对象
- 线程不安全
速记与实现:提供一个static引用给外部,私有化构造方法,暴露实例化方法,实例化方法中生产对象
- 线程安全
速记与实现:将实例化方法 synchronized 化
双重校验锁
速记与实现:第一重判断加快速度,第二重判断保证原子性。volatile保证禁止指令重排。
重点:
能不能不使用 valatile?不能!
- volatile关键字的重要性,禁止 new 指令重排序
- 一个new过程由三个原子操作:① 分配内存,② 调用构造器方法,执行初始化,③ 变量赋值。其中②,③可能发生指令重排序
- 如果一个线程在新建内存时优先执行了 ③ ,而另一个线程是可以发现为null是可以这个变量的,由于变量还未初始化,所以出错了。
能不能不使用 synchronized?不能!
- 保证大量线程进入方法时,互斥
synchronized 保证了有序性吗?没有
-
synchronized保证了内部代码块,单线程的有序性。
-
但是外部多线程环境在第一次判断为 null 时,不会进入锁,所以没有保证多线程的有序性。
public class Singleton { private volatile static Singleton singleton; private Singleton() {} public static Singleton getSingleton() { if(singleton == null) { synchronized (Singleton.class) { if(singleton == null) { singleton = new Singleton(); // volatile 保证这一行优先执行 } } } return singleton; } }
静态内部类
速记与实现:静态内部类也是利用了类加载机制,但是由于是类,所以没有实例化,节约了内存
枚举类
速记与实现:枚举类中定义枚举变量,因为枚举变量在java中是唯一的
破坏以上单例模式
要破坏单例模式,肯定要创建新的对象,创建对象的方式有四种
- new,无法破坏
- clone:实现cloneable接口,主动破坏
- 反序列化:实现servlized接口,原理也是反射机制破坏,通过反射拿到Object的构造函数,反射出单例类对象,从而创建了新的实例。解决办法:可以通过readResolve返回对象来防止破坏
- 反射:知道类结构,通过反射去拿构造器,改变构造器权限,就可以破坏。解决办法:可以通过构造器中抛出异常来破坏
19 建造者模式
速记:链式调用,一直返回当前对象
应用:当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式
实现:
-
在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
-
在Computer中创建一个private的构造函数,参数为Builder类型
-
在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram
-
在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例
-
在Builder中创建一个build()方法,在其中构建Computer的实例并返回
public class Computer { private final String cpu;//必须 private final String ram;//必须 private final int usbCount;//可选 private final String keyboard;//可选 private final String display;//可选 private Computer(Builder builder){ this.cpu=builder.cpu; this.ram=builder.ram; this.usbCount=builder.usbCount; this.keyboard=builder.keyboard; this.display=builder.display; } public static class Builder{ private String cpu;//必须 private String ram;//必须 private int usbCount;//可选 private String keyboard;//可选 private String display;//可选 public Builder(String cup,String ram){ this.cpu=cup; this.ram=ram; } public Builder setUsbCount(int usbCount) { this.usbCount = usbCount; return this; } public Builder setKeyboard(String keyboard) { this.keyboard = keyboard; return this; } public Builder setDisplay(String display) { this.display = display; return this; } public Computer build(){ return new Computer(this); } } //省略getter方法 }
使用方法:链式调用
Computer computer=new Computer.Builder("因特尔","三星")
.setDisplay("三星24寸")
.setKeyboard("罗技")
.setUsbCount(2)
.build();
20 原型模式(克隆模式)
速记:就是克隆模式,java 实现 cloneable 接口
应用:实现克隆操作,在 JAVA 继承 Cloneable,重写 clone()
实现:
- 实现cloneable接口嘛
21 适配器模式
速记:两个不相容接口的桥梁,使其能很好的工作
应用:转接头
实现:
- 适配器继承其中一个接口,并将另一个接口作为成员
- 使用者将适配器作为成员来使用
22 桥接模式
速记:抽象类中有一个接口成员,具体子类要实现这个接口成员,避免了继承
应用:抽象类和具体类之间进行桥接;减少子类的继承
实现:
- Abstraction:定义抽象接口,拥有一个Implementor类型的对象引用,比如shape
- RefinedAbstraction:子类中可以扩展Abstraction中的接口定义,比如红圈,绿圈
- ConcreteImplementor:实现Implementor接口,给出具体实现
23 组合模式
速记:用树形结构来表示一个组织
应用:树形结构的组织,文件夹管理
实现:
- 成员中有一个可以装本类成员的list即可、
24 装饰器模式
速记:动态的给一个对象添加职责,把一个对象包起来
应用:python @ 装饰器
实现:
- 抽象装饰器持有一个被装饰类的接口作为成员变量,
- 被装饰类接口变量,在构造方法中初始化
- 调用装饰器的时候,将对象传入构造方法即可
25 外观模式
速记:通过一个类,就可以new出来其他类,或者释放其他类,很方便
应用:电脑是一个外观,开机的时候把cpu,内存这些都启动了
实现:
- 在一个类中包含多个类的成员变量,构造方法中,new 出来多个成员变量即可
- 类中有多个方法可以操作成员变量的方法
26 享元模式(共享元对象模式)
速记:让对象不重复创建,共享元对象
应用:JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面
实现:
- 一个创建对象的工厂,维护一个hashmap容器
- 将对象放进hashmap中,查询hashmap,如果有,则返回,没有则新建
27 代理模式
速记: 代理模式有很多种,多是为了更好的控制另外一个对象,比如更好的缓存,更好的安全控制
应用:买火车票不一定要去火车站买,也可以去代售点买;windows里面的快捷模式;spring aop代理模式;vpn代理
实现:
- 代理类中拿到被代理类的引用,然后对引用private化,暴露自己的public接口来控制引用
28 责任链模式
速记:
应用:js中的事件冒泡机制;jsp servlet中的filter;卧槽,日志记录器也是吗
实现:
- 抽象类中设置下一个抽象类的引用
- 抽象类中对级别进行检验,如果某个当前抽象类级别够了,就调用具体类的实现方法
29 命令模式
速记:不同的命令封装成类,该类将请求类作为成员变量,并在构造方法中初始化
应用:命令行 command
实现:
- 请求者
- 命令类,该类将请求类作为成员变量,并在构造方法中初始化,提供调用请求者
- 调用者调用命令类,来处理请求
30 解释器模式
速记:定义新的规则来表示原来的东西
应用:编译器、运算表达式计算。
实现:
- 定义新的规则来表示原来的东西
31 迭代器模式
速记:iterator迭代器
应用:java迭代器
实现:
- 实现 hasnext(),next()方法,其实也是内部维护一个index++实现的
- 迭代器一般用于集合中,所以有个container
32 中介者模式
速记:中介类封装一系列对象的交互,接触交互的相互引用
应用:聊天室中一系列对象在相互交互,qq群
实现:
- 对象只需要和中介交互就行了