设计模式

### 1. 代理

静态代理:用继承或者实现接口来对原来的类加上额外的功能,和装饰者差不多。

  • 如果代理其他的类,就需要进行拓展
  • 一个类的功能有很多,同样的逻辑可能要写很多遍。

动态代理:在程序运动的时候产生代理类。

JDK

1
2
3
4
5
6
7
8
9
10
// loader  类加载器(findClass ,defineClasss,……)
// 目标类的接口,与之后的CGLIB有区别。
//给接口中的方法添加的功能。主要就是调用handler中的invoker()方法。
public static newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler)

InvocationHandler 中的invoke()方法
// proxy:代理对象
//method:目标方法(反射调用目标方法,method.invoke())
//方法的参数
public Object invoke(Object proxy,Method method,Object[] args){

主要流程:

Proxy内部实现一个代理类,代理类是在编译的时候生成的,代理类中要把handler给传进去。handler中有具体的实例,有一个Invoke方法,在方法中添加功能之后调用method.invoke(obj,args)来执行原来的功能。在代理类中的方法中执行中:让handler.invoke(method,target)。

总体的实现是在handler的invoke方法中。要想在代理类中调用handler.invoke方法,就要把handler传入代理类。也就是编写一个代理类文件然后编译。

1
newProxy->(创建代理对象Proxy,需要传入handler,将接口的所有方法改为handler.invoke(method,args))-》run method()-》handler.invoke(method,args)-> method.invoke(obj,args);

CGLIB

JDK需要目标类实现一个接口。

CGLIB生成目标类的子类。子类就是代理对象。也就是目标类不能是Final

2. 单例

饿汉-线程安全,直接用静态变量初始化。只有一个实例。

1
2
3
4
5
private static Singleton example=new SIngleton();

public static Singleton getInstance(){
return example;
}

双重校验锁

1
2
3
4
5
6
7
8
9
10
11
12
private static volitale Singleton example;
public static Singleton getInstance(){
//已经初始化,直接返回
if(example==null){
synchronized(Singleton.class){
if(example==null){//防止多次初始化
example=new Singleton();
}
}
}
return example;
}

3. 工厂

简单工厂

用一个工厂类来new各种不同类型的对象,就是说把对象的建立专门抽取出来。

工厂方法模式

定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。

与简单工厂不同的是,现在有很多不同类型的工厂。

一个产品的种类太多,可以分为很多个不同的大类,然后就将这不同的种类分到不同的大类中去。

  • 抽象工厂类。

    • 然后有具体的工厂实现类来实现抽象接口。在具体的工厂实现类中,生产不同的对象。
    • 在简单工厂的基础上多加了一层抽象工厂方法。就是因为实例可能有很多不同的对象,在一个工厂中生产,条件太多。

抽象工厂模式

  1. 对产品的整个一族创建工厂,而不是对产品的类别创建工厂。
  2. 产品族:一个产品中包含了很多个不同类型的产品部件:电脑=主板+CPU+显示器+…,pizza=各种各样的原料。
  3. 接口 PcFactory。
  4. 工厂:IntelFactory,AMDFactory.

适配器模式

  1. 继承和组合。

    1. 都是把一个类中的方法,弄到另一个类中去,组合是通过构造器注入的方法,也就是B类中有A类的成员变量,然后构造器注入。然后可以使用A中的方法
    2. 继承更简单,直接通过继承A的方式来获得A中的方法。

例:火鸡接口中没有鸭子接口的方法,用一个适配器来实现鸭子接口,用火鸡来模仿鸭子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Duck(){
public void quack();
}
public interface Turkey(){
public void gobble();
}
public class TurkeyAdapter implements Duck{
Turkey turkey;
public TurkeyAdapter (Turkey turkey){
this.turkey=turkey;
}
//火鸡叫模仿鸭子叫
public void quack(){

turkey.gobble();
}
}
  1. 将火鸡放到Adapter中可以通过构造器注入和继承两种方式。
  2. 对象适配器使用组合,类适配器使用继承。
  3. 如果接口非常多的话,遍历将会非常麻烦。

类适配器

1
2
3
4
5
6
7
8
//直接继承了火鸡类而不是使用构造器注入
public class TurkeyAdapter extends WildTurkey implements Duck {

@Override
public void quack() {
super.gobble(); //直接继承 被适配者
}
}