设计模式(思路)
设计模式七大原则:
单一责任:一个类尽量不要拥有太多的责任
接口隔离:接口设计的要尽量小,避免实现一个接口实现了多余的方法
依赖倒转:细节依赖于抽象,抽象不依赖于细节
里氏替换:尽量不要重写父类的方法
开闭原则:对扩展开放,对修改关闭
迪米特法则:最小知道原则,对尽量避免了解其他类的内部实现,减少耦合
合成复用原则:少用继承,而用依赖组合聚合
设计模式六大关系:
依赖 泛化 实现 聚合 组合 关联
创建型设计模式:
单例模式:
饿汉式实现
懒汉式实现- double-check(双重判断)
静态内部类实现
枚举实现
应用场景:需要频繁创建和销毁的对象,创建一次就够用而且需要频繁使用的对象(数据库访问,工具类)
源码中使用: RunTime类 利用饿汉式单例模式实现,static静态生成对象,系统调用时直接返回.
工厂模式:
抽象工厂: 工厂不只是一个类 而是一个工厂族,由接口定义,具体的想要的工厂实现由子类工厂提供。
源码中使用: Calendar类 利用简单工厂模式 ,对外提供一个静态方法,用来根据日期和地域生产Calendar对象。
满足原则: 开闭原则
原型模式:
浅拷贝: 实现cloneable接口,重写clone()方法.只会克隆对象的普通属性,如果有引用类型的属性则会都指向同一个地址引用(克隆一个人,如果这个人有朋友属性也是人类型,则克隆出来的所有复制品的朋友都是那一个人)
(String类型比较特殊,拷贝的也是同一个地址)
深拷贝:
- 对他的引用类型属性类也添加clone()方法。重写clone()方法时也要把该属性给clone;
- 利用序列化,反序列化。将一个类给序列化后,再进行反序列化 接收,完成克隆。
建造者模式:
角色:产品类 抽象建造者 实现建造者 指挥者
1.抽象建造者封装好对产品类的组装抽象
2.具体建造者实现抽象建造者,根据不同的具体建造者实现不同的产品细节建造
3.指挥者接收从客户发来的需求,根据需求分配建造者进行建造并组装成产品返回给客户
通过建造者建造一个产品类,使用户无需知道如何创建细节,用户只需提供所需要的型号给指挥者,指挥者负责具体产品类的建造。
源码中使用:StringBuilder
结构型设计模式
适配器模式
220V电压不能直接用于手机充电,用适配器 将220V转化为5V,然后给手机充电。
类适配器模式:通过继承要适配的220V的输出类,实现输出5V的接口,完成220V到5V的转化
对象适配器模式:通过组合220V的输出类,实现输出5V的接口,完成220V到5V的转换
接口适配器模式:有时候不想实现一个接口的全部方法,通过一个抽象类实现全部的方法(假实现),在通过继承该抽象类对需要用到的方法进行重写。
源码实现:SpringMVC设计中DispacherSevlet和Controller HandlerMapper之间关系
桥接模式
可乐,咖啡,茶 小杯中杯大杯
将抽象部分和实现部分分离,便于两个独立变化的维度来控制。高层只需要知道抽象部分和部分接口就行,具体业务实现由底层实现。
源码实现: JDBC中Driver用到了桥接模式,Connection是实现部分,Driver是抽象部分
装饰者模式
角色:Drink 具体的Drink 装饰者(Drink中加调料) 具体的装饰者
中心思想:用装饰者继承Drink,使得调料也是一个Drink类型,让调料一层一层包裹在Drink外边,使得Drink添加到调料中 装饰者 zsz = new 装饰者(Drink);
jdk源码实现: javaIO流中
InputStream接口为被装饰者。其中FilterInputStream为装饰者,用来包裹被装饰者,其他
FileInputStream,ByteArrayInputStream,StringBufferInputStream,ObjectInputStream都是被装饰者具体实现。
组合模式
Component抽象类 Composite枝干类 Leaf叶子类
组合模式满足一个树状结构,所有类都继承Component抽象类,枝干类包含很多叶子类,具有添加,删除叶子类的功能。叶子类是最小类,不可再分
适用条件:结构满足树形结构,要遍历整个树形结构。枝干类与叶子类有很大相似性,
jdk源码:HashMap的实现原理
Map接口相当于Component AbstractHashMap实现了Map接口,也相当于Component。
HashMap继承了 AbstractHashMap相当于 Composite
Node 作为叶子节点Leaf
享元模式---共享 对象
思想:尝试使用已经存在的对象,如果未存在则新创建,如果存在就重复利用
内部状态:存储在享元对象内部,不会随环境改变而改变的状态 (五子棋 的棋子颜色)
外部状态:是外部的一个标记,随环境改变而改变,不可共享 (五子棋 棋子的位置)
数据库连接池技术,字符串缓存池技术
通过一个享元类,判断是否需要创建新的需要的对象。
jdk源码:Integer.valueof(-128 127)时,无需new新的Integer对象,直接使用已经存在的
代理模式Proxy
静态代理 JDK动态代理 Cglib动态代理
不希望客户直接访问被代理类。通过代理类,对被代理类的功能完成实现,并加以控制,
静态代理: 代理类实现被代理类的接口,并聚合进来,通过构造方法传进来,完成对被代理类的功能的重写,或添加功能
JDK动态代理: 被代理类实现了接口。通过一个代理类工厂,将被代理类 通过构造方法传入,使用getInstance()方法 动态的为被代理类创建一个代理类返还给客户端。客户端通过得到的代理类来完成功能。
Cglib动态代理:被代理类没有实现接口。
命令模式Command
发布命令的将军,執行命令的底层士兵,命令集类
核心思想:将军通过命令集合来调动士兵,而不是直接调动士兵。通过命令 完成了将军和士兵的解耦。
士兵聚合到命令集中,命令集聚合到将军类的集合中,命令分为调用和撤销
使用:
对将军类中所有命令集初始化,全部赋予空命令
为命令集中插入具体命令
调用该命令
访问者模式Visitor
完成稳定的数据结构和对数据结构多样的操作分离
核心代码: 将数据结构类中有一个accept用来接受访问者,并将调用访问者的方法并将自身传给访问者。
观察者模式Observer
被观察者(气象站) 观察者们(各大天气网站)
被观察者拥有一个观察者集合,可以添加和删除观察者们(绑定和解除绑定)
当被观察者发现信息被修改dataChange()会通知所有绑定的观察者们notifyAlll()
观察者们拥有接受信息并做出改变的功能
状态模式Statement
状态组Statement 环境Context
所有状态都继承Statement接口,不同的状态根据状态的不同,所实现的具体方法也不同
状态类
核心思想:把每个状态封装成具体的类聚合到环境(Context)类当中
策略模式strategy
在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。
核心思想:把不同行为封装成不同的类,聚合到环境(Context)当中