单例的几种方式。
public class Single{
private static volatile Single single;
private single(){}
public static Single getSingle(){
if(single == null){
synchronized(Single.class){
if(single == null){
single = new Single();
}
}
}
return single;
}
}
在dcl中volatile为了防止指令重排序而引入的。了解下single = new Single();这段代码其实不是原子性的操作,它至少分为以下3个步骤:
- 给single 对象分配内存空间
- 调用Single类的构造函数等,初始化single 对象
- 将single对象指向分配的内存空间,这步一旦执行了,那single对象就不等于null了
破坏单例模式的几种方法
- 实现序列化接口破坏单例模式,在反序列化时会使用反射机制创建一个新的对象。
- 解决方案是写一个readResolve方法返回实例,在反序列化代码中会判断hashReadResolveMethod,如果有会优先调用readResolve方法。
- 使用反射破坏单例模式
- 克隆破坏单例模式
单例模式
- 单例模式主要确保一个类只有一个实例
动态代理模式
- 为对象提供一种代理方式,控制对象的访问权限。
- jdk动态代理主要是实现invocationHandler接口,通过执行Proxy.newProxyInstance(classLoader,interface,this);创建一个代理对象,然后调用invoke方法执行代理对象的方法。
工厂模式
- 简单工厂模式(静态工厂)
- 虽然某种程度上符合设计原则,但实际使用较多。
- 工厂方法模式
- 不修改已有类的前提下,通过增加新的工厂类实现扩展。
- 抽象工厂模式
- List list1 = new ArrayList();
- List list2 = new LinkedList();
- 这个就是抽象工厂。List是一个接口,ArrayList和LinkedList根据自己的细节去完成自己的实现。
建造者模式
- 应用场景:需要生成的产品对象有复杂的内部结构,且这些产品对象具有共同的特性。
- 个人理解:现在有10个独立的方法,完成业务A可能需要其中的5个方法那么就调用这5个方法去完成业务A,如果业务B需要8个方法那么就去调用对应的8个方法。
- 举例子:比如一个汽车组装工厂,低配汽车可以组装如轮胎+车架+普通座椅完成组装,高配的汽车组装可以用轮胎+车架+天窗+真皮座椅+豪华音响组装完成。
链式编程
原型模式
- 原型模式就是clone()
适配器模式 adaper
- 使用场景, 当方法A要调用方法B时,A不能直接访问B,此时在A调用B时插入T方法,将A的参数转换成B所需要的入参。
桥接模式
- 如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使用它们在抽象层建立一个关联关系。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
外观模式
- 一个功能的实现需要多个系统互相调用错综负责,外观模式是给这些个错综调用的系统提供一个接口,用户尽管去调用,不用考虑他是怎么实现的。
中介者模式
- 解决多系统互相调用的问题,使用中介者模式,各系统不在相互调用,而是独立出一个中间服务,各系统调用中间服务交互信息,经典的实现就是消息中间件。
策略模式 strategy
- 根据不同的条件选择执行不同的方法
- 比如我在计费系统中的使用,前端页面有40多种资源类型,后端处理的时候肯定不能写40个接口来返回参数
- 我根据策略模式来实现的,在controller里面我把40个类型的service存到了一个map的Value里面,key为账单对应的typeNo(唯一的),@PostConstruct进行初始化加载。
- 前端调用时只需要传typeNo,后端接收到用typeNo到map里面去拿对应的value就是service,调用getInfo方法,可以获取到对应类型的资源账单。
装饰器 Decorator
- 对一个现有的对象进行属性的设置,比如创建一个订单,我们可以定义一个方法填充他的属性,这就是最简单的装饰者模式的实现。
观察者模式
观察者模式的组成通常有三部分,观察者,被观察者,事件。多个观察者实现同一个观察者接口,实现监听方法,监听方法中包含Event事件参数,被观察者类的实现通常先创建一个列表泛型为观察者接口,这样就可以把不同的观察者添加到列表中,被观察者可以根据具体操作触发不同的事件,然后循环列表进行观察者的监听调用,观察者根据事件类型响应对应的业务操作,这样观察者模式就完成了。
组合模式
享元模式
共享源数据,把数据共享,不要每次用的时候都去申请,比如线程池,连接池,String str = "abc"; jvm常量池
责任链模式
- 适用场景:比如一个请假流程,3天以下研发组长审批,3-5天需要部门经理批,5天以上需要总监审批。
- 现在张三要请5天假,组长审批通过了,在调用下一级审批,部门经理审批通过了,再调用总监审批。
- 每一次只需要完成自己的工作无需关心上级或下级是如何完成的。调用方也无需关心链条是怎么执行的。
- 实现方法:首先要有一个抽象类,包含处理方法,和一下层对象的设置方法。
- 调用流程:level1.setNextLevel(level2);level2.process,在level1的执行执行法中调用nextLevel.process,以此类推完成整个责任链的调用。
命令模式
- 命令模式用于完成单一操作,命令模式包括 do 和 undo两部分,do为操作的执行,undo为操作的撤销。
备忘录模式
- 备忘录模式允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
- 我们可以创建一个和要保存的对象属性完全相同的对象用来存储对象属性,同时将每次复制的对象存到stack栈中,这样在恢复的时候根据stack的后进先出规则完成数据的恢复。
模板模式
- 模板类规定应该执行哪些方法,比如需要顺序执行方法A、B、C、D最终完成一个程序,但是方法的具体实现细节需要实现类自己去完成。
状态模式
- 根据不同的状态执行相同的方法,方法的具体实现由状态来决定
- 状态模式可以代替if else
- 代码实现:
- 定义一个抽象的状态类status,一个doWork抽象方法由子类去实现具体的逻辑。
- 如果有状态加入,则继承status抽象类,重写doWoke方法,执行当前状态对应操作。