常用设计模式

外观(门面)模式

化零为整,把零碎的功能拼成一个整体,对外提供一个统一接口,用来访问子系统中的多个接口。

总结

解耦,不需要一个个对接,使用简单。

 

单例模式

负责创建对象,同时确保只有单个对象被创建。

饿汉式

线程安全,在类加载时就会进行初始化,访问时直接使用。

public class Student {

    private static final Student student = new Student();
    private Student() {}

    public static Student getInstance() {
        return student;
    }
}

在类加载的时候便完成了实例化。

饱汉(懒汉)式

需要使用时才会去创建实例。

public class Student {

    private volatile static Student student;
    private Student() {}

    public static Student getInstance() {
        if (student == null) { 
            synchronized (Student.class) {
                if (student == null) {
                    student = new Student();
                }
            }
        }
        return SINGLETON;
    }
}

如果要保证线程安全,需要添加双重锁,当两个线程同时执行 getInstance 时,结果都为 true,会导致一起进入排队状态,从而重复创建新的对象;

所以需要双重判断,预防多线程重复创建。

静态内部类

public class Student {

    private Student() {}
    private static class Instance {
        private static final Student student = new Student();
    }

    public static Student getInstance() {
        return Instance.student;
    }
}

线程安全,只有使用时才会创建实例,不会造成资源浪费的问题。

枚举式

public class Student {

    private enum StudentEnum {
        INSTANCE;
        private final Student instance;
  
        StudentEnum() {
            instance = new Student();
        }
        private Student getInstance() {
            return instance;
        }
    }

    private Student() {}
    public static Student getInstance() {
        return StudentEnum.INSTANCE.getInstance();
    }

}    

线程安全,只会装载一次,无论是序列化、反序列化、反射还是克隆都不会新创建对象。

 

简单工厂 & 抽象工厂

工厂模式将对象的创建和使用分离,属于一个产品系列,而抽象工厂是多个产品系列一个工厂类。

//宝马系列
BMWCar bmBean = CarFactory.create(Car.BMW); BMWX1 x1 = bmBean.getX1();
x1.drive();
BMWZ4 z4 = bmBean.getZ4();
z4.drive();
//奔驰系列 BenZCar benZBean
= CarFactory.create(Car.BenZ);
BenZSUV suvBean = benZBean.getSUV(); suvBean.speed(); suvBean.stop();

总结

解耦,提高扩展,但是每次新增需要修改原代码。

 

构键者模式

用于一步步创建复杂对象,一般分产品类,构键类和组装类,通常用于配置工具类使用。

 

代理模式

为两者之间提供一个代理对象(拦截层),并且目标对象只能被代理对象访问,调用目标对象都要先通过代理对象。

静态代理

目标对象和代理对象实现共同的接口或继承相同的父类,在不修改目标对象的前提下进行扩展。

平时接手代码,就可以在不修改原代码的基础上扩展原有功能。

总结

代理对象需要与目标对象实现一样的接口,一对一模式,会导致代理类比较多;

接口修改后,目标对象与代理对象都要修改,维护成本高,适合目标类比较少的情况。

动态代理

一对多模式,一个代理类可利用反射机制代理多个委托类,并且是在运行时创建动态代理类。

JDK接口动态代理

代理对象不需要实现接口,目标对象必须实现接口

Proxy.newProxyInstance(classLoader 类加载器, classInterfaces[] 接口列表, InvocationHandler 拦截处理类);

总结

可以将代理类的创建推迟到运行时期,代理类通过 JDK 的 API 动态在内存中创建,这样就可以大大减少代理类的创建和维护,但前提是目标类必须实现接口。

Cglib子类动态代理

不强制实现接口,在内存中动态的创建一个目标类的子类对象,从而实现对目标类的代理。

总结

通过 ASM 框架转换字节码并生成新类,不能使用 final 修饰代理方法。

可以直接生成二进制 class 文件,也可以在类被加载到 Java 虚拟机之前改变类行为。

 

责任链模式

请求在链上一个个传递,直到链中某个对象处理。

总结

可以控制请求顺序,新增不用修改原代码,逻辑解耦,单一职责,效率不高,比较复杂,符合多个认证或者校验等场景。

 

享元模式

共享基本的单元、元件,提升已有元件的复用率,减少重复制造开销。

代码中主要分元件跟工厂类,工厂中编写获取方法,方法判断该元件是否存在,如果不存在新建元件,存入共享池中,如果存在直接从池中获取返回,类似单例。

总结

减少了资源的使用,但是增加了代码的复杂程度。

 

模板方法模式

在一个抽象类公开定义了抽象的执行方法跟逻辑方法,子类继承实现父类逻辑方法,但调用将以抽象类中定义的执行方法执行。

public abstract class Student {

    public final void getInfo() {
        info1();
        info2();
        ToastUtils.show("获取信息成功");
    }

    /** 逻辑方法 */
    abstract void info1();
    abstract void info2();

}

只需要继承方法就能实现代码复用,不过父子类存在耦合。

 

热门相关:首席的独宠新娘   大神你人设崩了   天启预报   第一神算:纨绔大小姐   网游之逆天飞扬