常见设计模式
1.单例模式
- 饿汉式
类加载到内存之后,就实例化一个单例,由jvm保证线程安全。简单实用,唯一缺点:无论类用到与否,类装载时都会实例化出这个对象,
代码示例:
public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01() {};
public static Mgr01 getInstance() {
return INSTANCE;
}
}
- 懒汉式
达到了按需初始化对象,但是造成了线程安全问题,使用synchronized加锁和双重检测解决,带来了效率下降的问题。注意:实例化的对象要用volatile关键字修饰,防止指令重排(volatile关键字是使用jvm的内存屏障来保防止指令重排,即在该对象读指令前加上loadload指令,在读指令之后加上loadstore指令,在该对象的写指令之前加上storestore屏障,在写指令之后加上storeload屏障,指令重排可能会导致对象在半初始化的时候被别的对象读取)
示例代码:
public class Mgr06 {
private static volatile Mgr06 INSTANCE; //JIT
private Mgr06() {
}
public static Mgr06 getInstance() {
if (INSTANCE == null) {
//双重检查
synchronized (Mgr06.class) {
if(INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
}
- 静态内部类实现
JVM保证单例,加载外部类时,内部类不会被加载,一个类jvm只会加载一次,这样也可以实现懒加载
示例代码:
public class Mgr07 {
private Mgr07() {
}
private static class Mgr07Holder {
private final static Mgr07 INSTANCE = new Mgr07();
}
public static Mgr07 getInstance() {
return Mgr07Holder.INSTANCE;
}
}
- 枚举类实现单例
不仅可以解决线程同步,还可以防止反序列化。完美的单例实现,但是有时候会觉得很别扭
示例代码:
public enum Mgr08 {
INSTANCE;
public void method1(){
...业务代码....
}
//直接这么调用
public static void main(String[] args) {
Mgro8.INSTANCE.method1();
}
2.策略模式
按照一定的策略来达到某种目的,例如,对一组数字排序、对猫排序、对狗排序,这样可以将排序的策略抽离出来,用作参数传入比较器中,就能达到对这些不同类型的是事物进行排序的目的。可以达到关闭修改,开放扩展的目的
示例代码:
//主方法
public class Main {
public static void main(String[] args) {
//int[] a = {9, 2, 3, 5, 7, 1, 4};
Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
//Dog[] a = {new Dog(3), new Dog(5), new Dog(1)};
Sorter<Cat> sorter = new Sorter<>();
//java1.8lambda表达式
/* sorter.sort(a, (o1, o2)->{
if(o1.weight < o2.weight) return -1;
else if (o1.weight>o2.weight) return 1;
else return 0;
});*/
//传一组猫,传一个猫的排序策略
sorter.sort(a,new CatHeightComparator ());
System.out.println(Arrays.toString(a));
}
}
//接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
default void m() {
System.out.println("m");
}
}
//比较器
public class Sorter<T> {
public void sort(T[] arr, Comparator<T> comparator) {
for(int i=0; i<arr.length - 1; i++) {
int minPos = i;
for(int j=i+1; j<arr.length; j++) {
minPos = comparator.compare(arr[j],arr[minPos])==-1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
//sort(int)
void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//猫的比较策略
public class CatHeightComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
if(o1.height > o2.height) return -1;
else if (o1.height < o2.height) return 1;
else return 0;
}
}
3.工厂模式
- springIOC:springIOC即spring的控制反转,为什么叫控制反转,是因为原本由我们手工new去实例化对象的操作交给了spring,它通过配置文件来实例化对象,所以spring相当于一个大的工厂,产生我们需要的实例化对象;它有时也叫springDI,即依赖注入,例如某些对象有一些对象属性,这些对象属性可以通过依赖注入的方式注入进该对象
4.门面模式
5.调停者模式
6.责任链模式
示意图:
7.observer观察者模式
8.chain of responsibility责任链模式
9.proxy静态代理和动态代理
10.builder(构建者)
11.adapter(转换器)
12.iterator(迭代器)
13.decorator(装饰器)
14.composite(组合)
15.flyweight(享元)
经常和组合一起使用,如常量池中的值,初始化以后,如果其他对象用到这个值,直接取出来用,即可,也可将多个数据组合成一个,让别的对象调用
16.visitor(访问者)
17.bridge桥接
18.command命令
19.prototype原型
20.memento备忘录
记录状态,便于回滚,记录快照 存盘,如画图的回退,游戏的存档,对象实现serializable接口将对象序列化,就可以将对象通过objectoutputstream存盘
21.templatemethod模板方法
钩子函数,如window listener等这一类已经写好了模板方法,实现了模板方法中的具体方法,就可以让整个方法按照模板去执行,同时也实现了我们的私有逻辑