• 简单的设计模式


    一,单例模式

    顾名思义,单例对象能保证在一个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哪个子类

  • 相关阅读:
    【3】网站搭建:分页功能
    mapserv和mapserv.exe的区别
    WMS请求GetCapabilities,变成下载mapserv.exe解决办法
    get和post的区别
    实现ajax异步请求
    Thinkphp3.2 Widget的扩展
    Thinkphp3.2 路由是使用
    Thinkphp3.2 TagLib的使用
    Thinkphp下实现Rbac
    Thinkphp下实现分页
  • 原文地址:https://www.cnblogs.com/yeg0zj/p/14469264.html
Copyright © 2020-2023  润新知