设计模式复习总结


别问 问就是为了面试豁出了老命

设计模式的六大原则

  1. 依赖倒置原则
    • 针对接口编程,具体依赖抽象编程,但是抽象不依赖具体编程
    • 也就是说接口中来抽象出有什么方法,用接口来架构,用类来实现
  2. 开闭原则
    • 对拓展开放,对修改关闭
    • 用抽象构建架构,用实现扩展原则
    • 可见依赖倒置才能有开闭原则的实现
  3. 里氏替换原则
    • 出现基类的位置可以出现子类,但是出现子类的位置不能出现基类
  4. 迪米特法则
    • 也叫做最少知道原则
    • 一个实体应该尽可能的不与其它的实习发生相互作用
    • 也就是说一个类和另一个类尽量不要有继承这类关系
  5. 合成复用原则
    • 尽可能的使用合成,聚合,而不去使用继承
  6. 接口隔离原则
    • 使用多个隔离的接口,比使用单个接口好
    • 也就是说一个实体的实现应该用尽量小的接口,不应该再去依赖那些不需要的接口

工厂方法

简单工厂

- 如果说生产A披萨,B披萨
- 那么我们需要创建披萨接口,A,B披萨都要实现这个接口
- 之后在披萨的生产工厂中,通过传递字符串"A","B"来创建相应的披萨并返回

工厂方法

- 从简单工厂上已经解决了生成某类披萨的模式,但是由于字符串的传递导致如果有新款披萨,那么就需要修改工厂中的创建方法。违反开闭原则(这里暂时不变)
- 假如披萨的产地需要增加,那么一个是N地,一个是M地
- 那么就需要进一步的抽象,N地,M地都去实现工厂的接口
- 之后再在实现的工厂的接口中的方法里去制造披萨
- 这样,产地将可以在不破坏工厂的情况下动态添加
- 但是在创建产地的时候,必须要知道产地的方法名等信息

抽象工厂

- 接着工厂方法继续说, 如果不同的产地生产不同的披萨呢
- 那么继续把工厂抽象,不同的产地都继承抽象的工厂接口
- 然后这些产地工厂再去实现类似简单工厂的不同的披萨生产

简单工厂就是一个地方生产不同的任何产品
工厂方法则是生产固定的产品
抽象工厂则是可以生产不同产品族的任何方法

单例模式

  1. 懒汉式
    • 也就是说,只有用的时候才回去看看是不是存在单例,存在的话直接反回,不存在的话再创建
    • 存在线程安全问题,区别在于是否加了 synchronized 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class LanHanSingleton {

private static LanHanSingleton lanHanSingleton ;

private LanHanSingleton(){

}

public static synchronized LanHanSingleton getSingleton(){
if (lanHanSingleton!=null){
}else {
lanHanSingleton = new LanHanSingleton() ;
}
return lanHanSingleton ;
}
}

```
2. 饿汉式
- 和懒汉式相反,饿汉式是直接就创建单例对象
- 不存在是不是线程安全问题
- - 由于static是在类加载期间就会被处理,因此启动jvm时,只存在一个静态类,而且是线程安全的

``` java
public class EhanSingleton {

private static EhanSingleton ehanSingleton = new EhanSingleton() ;
private EhanSingleton(){

}

public static EhanSingleton getSingleton(){
return ehanSingleton ;
}
}
  1. 静态内部类
  • 其实与饿汉式是一样的,都是建立在static,在类加载的时候处理,来保证线程安全
  • 但是静态类如果没有被使用的话,是不会创建的,这样子做到了延迟加载的效果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class InnerStaticSingleton {


    private static class SingletonHolder{
    private static final InnerStaticSingleton Instance = new InnerStaticSingleton() ;
    }

    private InnerStaticSingleton(){

    }

    public static final InnerStaticSingleton getSingleton(){
    return SingletonHolder.Instance ;
    }
    }
  1. 枚举

    • 枚举的本身就是private修饰的构造方法
    • 枚举实例都是static final类型的
    • 枚举可以直接序列化
  2. 双重校验锁

  • 问题分析:
    • 如果使用的是懒汉式加载,每次都调用synchronized去同步消耗资源较大
  • 问题处理:
    • 第一次校验不上锁,保证了不会每次都用synchronized同步去消耗资源
    • 第二次校验上锁,存在特殊情况,A线程进行第一次校验的过程,校验结果是对象为null,这时候A线程被阻塞,B线程也进行校验,发现对象为null,这样会存在创建两次对象的情况,因此选择第二次继续校验,保证了对象只创建一次
    • jvm的指令重排效果下,初始化双重校验锁的类,和给doublecheckSingleton赋值的顺序是不一定的
      • 可能会出现,双重校验锁的类刚刚创建完,就给doublecheckSingleton被赋值了,是非null的,因此会发生错误
      • 使用volatile禁止指令重排,才得以保证安全性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DoubleCheckSingleton {

private static volatile DoubleCheckSingleton doubleCheckSingleton ;
private DoubleCheckSingleton(){

}

public static DoubleCheckSingleton getDoubleCheckSingleton(){
if (doubleCheckSingleton==null){
synchronized (DoubleCheckSingleton.class){
if (doubleCheckSingleton == null){
doubleCheckSingleton = new DoubleCheckSingleton() ;
}
}
}

return doubleCheckSingleton ;
}
}