设计模式
一、单例
保证一个类 只有一个实例,并提供一个全局访问点。
需要私有化构造方法
private Singleton(){
}
1、饿汉
private static final Singleton INSTANCE = new Singleton();
2、懒汉
- 双检锁
// volatile 可以保证可见性,禁止指令重排
private static volatile Singletion instance;
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
- 同步方法
private static Singletion instance;
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
- 静态内部类,即实现了延迟加载,也保证了线程安全。
类的加载和初始化是分开进行的,且初始化发生在类首次使用时。静态内部类
SingletonHolder
被加载并初始化的时刻是在其包含的静态成员被访问
时。
JVM 的类初始化机制
- 懒加载
- 线程安全:类的初始化过程由 JVM 来控制,它保证了多线程之间对于
Singleton
实例的唯一性和可见性,且只会执行一次初始化。
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
- 枚举 天然单例
二、原型
浅克隆 深克隆
三、工厂
1、简单工厂
通过静态方法的参数不同,创建不同的对象
2、工厂
一个工厂;创建对象
3、抽象工厂
多个工厂;创建不同的对象
代理
不能直接访问真实对象,需要添加一个代理对象
装饰
添加新的功能。实现,将被装饰的类作为一个成员变量 在编译期间,关系就已经确立
适配器
把原本不兼容的接口通过适配修改做到统一。
将一个类的接口转换成另外一个接口,接口类型通过set方法注入。 io 流 。客户可以指定装饰哪一个类
桥接
业务场景两个维度,如形状和颜色 ,将第二个维度抽象成接口,通过set方法进注入。
- 抽象部分:提供高层控制逻辑,依赖于完成底层实际工作的实际对象。
- 实现部分:为所有具体实现声明通用接口。抽象部分仅能通过在这里声明的方法与实现对象交互。
桥接模式的作用
- 分离抽象与实现
- 较少类的数量
- 提高系统的可扩展性
- 促进服用
应用场景
- JDBC 驱动
- slf4j
- 银行转账
- 转账分类:网上转账,柜台转账,ATM转账 抽象层
- 转账用户类型:普通用户,银卡用户,金卡用户... 实现层
- 消息管理
- 消息类型:即时消息,延迟消息 抽象层
- 消息分类:手机短信,邮件,站内信... 实现层
门面
复杂的子系统对外提供一个统一的接口。
享元
组合
组合对象与单个对象
模板
利用抽象类的抽象方法。
在方法中定义算法的骨干部分,将实现延迟到子类中。
应用场景
- 发生短信,有 阿里云、华为云、腾讯云等。
允许子类在不修改父类的代码的情况下重写算法的特定步骤。
模板方法建议将算法分解为一些列步骤,然后将这些步骤改写为方法。
适用场景
- 只希望客户端扩展某个特定算法步骤,而不是整个算法或者算法的结构,可使用模版方法模式。
策略
应用场景
- 在推送报文的时候,有很多个接口,每个就是就相当于一个策略。
- 导航时,不同的交通工具,路线是不一样的
- 购物时,计算优惠,不同的活动,计算方法是不一样的
实现多个策略。
定义一些列的算法,将每一个算法封装起来,并且使他们可以相互替换。
案例
开发导航功能时,需要开发多种交通工具的导航。汽车导航,自行车导航,步行导航。这个时候就可以考虑使用策略设计模式来实现。
名为上下文的原始类必须包含一个成员变量来存储对于每种策略的引用。
上下文不执行任务,而是将工作委派给已连接的策略对象。
命令
将一个请求封装成一个对象
责任链
应用场景 简单的工作流可以通过责任链设计模式来实现。
在上报审批的流程中,简单的分为几级审批,这个可以通过责任链设计模式来实现,如果更复杂的需要通过 activiti 等工作流引擎来实现。
多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
可动态指定一组对象处理请求,或添加新的处理者。
需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
允许你将请求沿着处理者链进行发送。收到请求后,每个处理者都可以对请求进行处理,或者将请求传递给链中 的下一个处理者。
案例
用户登录认证,需要验证用户的身份,用户的角色,用户的权限。这个时候就可以使用责任链模式来实现。
优化前
优化后
状态
观察者
订阅模式
中介者
迭代器
访问者
备忘录
解释器
interpreter design
意图: 给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。 主要 解决: 对于一些固定文法构建一个解释句子的解释器。 何时使用: 如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。 如何解决: 构建语法树,定义终结符与非终结符。 关键代码: 构建环境类,包含解释器之外的一些全局信息,一般是 HashMap。 应用实例: 编译器、运算表达式计算。 优点: 1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。 缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。 使用场景: 1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可以用一种简单的语言来进行表达。 3、一个简单语法需要解释的场景。 注意事项: 可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。