简单的设计模式

一,单例模式

顾名思义,单例对象能保证在一个JVM中,该对象只有一个实例存在。

饿汉式:立即记载,线程安全,对象过早创建容易占用内存,资源浪费

public class Singleton {

//创建 SingleObject 的一个对象
private static Singleton singleton = new Singleton();

//让构造函数为 private,这样该类就不会被实例化
private Singleton(){}

//获取唯一可用的对象
public static Singleton getSinglton(){
return singleton;
}

public void showMessage(){
System.out.println("Hello World!");
}
}

调用:

public class SingletonPatternDemo {
public static void main(String[] args) {

//不合法的构造函数
//编译时错误:构造函数 SingleObject() 是不可见的
//SingleObject object = new SingleObject();

//获取唯一可用的对象
Singleton object = Singleton.getSinglton();

//显示消息
object.showMessage();
}
}

1,为什么要创建一个private Singlton(){}无参构造?

禁止其他程序创建该类的对象

2,为什么本类new出来的对象要私有和静态化?

私有是不能直接访问,通过指定方法访问,也是封装的体现。静态修饰是因为单例对象singlton能够被外部调用,调用方法getSinglton是静态的,所以对象必须也是静态的

 

懒汉式

延迟加载,降低内存消耗,线程不安全,如果想要线程安全需要增加sycronized关键字

public class Singleton {

//创建 SingleObject 的一个对象
private static Singleton singlton;

//让构造函数为 private,这样该类就不会被实例化
private Singleton(){}

//获取唯一可用的对象
public static Singleton getSinglton(){
if(singlton==null){
singlton = new Singleton();
}
return singlton;
}

public void showMessage(){
System.out.println("Hello World!");
}
}

加了锁之后懒汉式效率会降低,如何提高效率?

DCL双检查锁机制。

1,拿到锁之前检查是否是空对象,2,new对象之前检查是否是空对象

为什么拿锁前要判断?因为要提高效率,已有对象直接跳过,不用去争夺锁

为什么new对象之前还要判断?因为这里的singltonSinglton对象的引用,前一个线程如果已经创建了对象那么singlton就不是null,不做判断下一个线程进来就会重复new对象,就不是单例了。

为什么要加volatile关键字?

因为假设一个线程new出一个对象的时候,还没执行init()构造方法,就发生了指令重排序,没来的及赋值就指向了对象的引用,这个值就是0。此时另一个线程来了,判断对象不为空就拿去用了,使用了半初始化状态的对象。为了避免发生这种问题所以加入volatile关键字

public class Singleton {

    //创建 SingleObject 的一个对象
    private static volatile Singleton singleton;

    //让构造函数为 private,这样该类就不会被实例化
    private Singleton(){}

    //获取唯一可用的对象
    public static Singleton getSinglton(){
        // 第一次检查instance是否被实例化出来,如果没有进入if块
        if(singleton == null) {
            synchronized (Singleton.class) {
        // 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

    public void showMessage(){
        System.out.println("Hello World!");
    }
}

二,装饰者模式

装饰者模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它是作为现有的类的一个包装。

装饰者模式和静态代理很类似,装饰者(Decorator)和被装饰者(Decoratee)都实现一个接口,都是修改原有被装饰、被代理的方法。

区别在于装饰者模式构造方法不一样,被装饰对象是直接传过去的,而静态代理是直接new的代理对象

代理模式注重的是对对象的某一功能的流程把控和辅助,代理类可以对它的客户隐藏一个对象的具体信息,它可以控制对象做某些事;装饰模式注重的是对对象功能的扩展,不关心外界如何调用,只注重对对象功能加强,装饰后还是对象本身。

装饰者模式用途:IO流,层层增强功能。

三,代理模式

静态代理的缺陷:程序员要手动为每一个目标类编写对应的代理类。动态代理解决了这个问题。

JDK动态代理:

主要提供2个类Proxy和InvocationHandler

Proxy.newProxyInstance()用于创建代理对象的实例,InvocationHandler.invoke()用于实现代理对象的方法增强细节

JDK的动态代理使用Java的反射技术生成动态代理类,只能代理实现了接口的类, 没有实现接口的类不能实现动态代理。

CGLIB动态代理运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法,在子类中采用方法拦截的技术拦截所有父类方法的调用,不需要被代理类对象实现接口,从而CGLIB动态代理效率比Jdk动态代理反射技术效率要高。

 四,工厂模式

一个接口有多个实现类的情况下,具体创建哪个实现类的对象交由工厂去管理,也就是当需要用哪个子类的时候就由工厂去new哪个子类

原文地址:https://www.cnblogs.com/yeg0zj/p/14469264.html