栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式之创建者模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式之创建者模式

单例模式

饿汉式:类加载就会导致该单实例对象被创建

懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会被创建


饿汉式实现

1、 饿汉式方式1 静态成员变量方式

public class Singleton{
    //1.私有构造方法,外界无法创建对象
    private Singleton(){}
    //2. 在本类中创建本类对象
    private static Singleton instance = new Singleton();
    //3. 提供一个公共的访问方式,让外界获取该对象。静态方法只能访问静态变量
    public stataic Singleton getInstance(){
        return instance;
    }
}

2、饿汉式方式2 静态代码块方式

public class Singleton{
    private Singleton(){}
    //只是申明Singleton类型的变量,没有赋值创建变量,默认为null
    private static Singleton instance;
    //在静态代码块中进行赋值
    static {
        instance = new Singleton();
    }
    public static Singleton getInstance(){
        return instance;
    }
}

饿汉式缺点:类加载但不使用会造成内存浪费


懒汉式实现

1、线程不安全

public class Singleton{
    private Singleton(){}
    //申明Singleton类型的变量,没有赋值,默认为null
    private static Singleton instance;
    //3. 提供一个公共的访问方式,让外界获取该对象。静态方法只能访问静态变量
    public static Singleton getInstance(){
        // 判断instance是否为null,如果为null表示还没有创建
        // 如果没有创建,就创建一个,否则就直接返回
        if(instance == null){
            // 多个线程可能都会进入判断
            instance = new Singleton();
        }
        return instance;
    }
}

2、线程安全

public class Singleton{
    private Singleton(){}
    //申明Singleton类型的变量,没有赋值,默认为null
    private static Singleton instance;
    //3. 提供一个公共的访问方式,让外界获取该对象。静态方法只能访问静态变量
    public static synchronized Singleton getInstance(){
        // 判断instance是否为null,如果为null表示还没有创建
        // 如果没有创建,就创建一个,否则就直接返回
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

缺点:加锁性能低下

3、双重检查锁

public class Singleton{
    private Singleton(){}
    //申明Singleton类型的变量,没有赋值,默认为null
    private static Singleton instance;
    //3. 提供一个公共的访问方式,让外界获取该对象。静态方法只能访问静态变量
    public static synchronized Singleton getInstance(){
        // 第一次判断如果instance的值不为null,不需要抢占锁,直接返回
        if(instance == null){
            synchronized (Singleton.class){
                // 第二次判断是否为null
                if(instance == null){
                     instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

缺点:在多线程情况下,可能出现空指针情况,出现原因是JVM优化和指令重排,解决方法是使用volatile关键字保证可见性和有序性

最终版本:

推荐使用

public class Singleton{
    private Singleton(){}
    //申明Singleton类型的变量,没有赋值,默认为null
    private static volatile Singleton instance;
    //3. 提供一个公共的访问方式,让外界获取该对象。静态方法只能访问静态变量
    public static synchronized Singleton getInstance(){
        // 第一次判断如果instance的值不为null,不需要抢占锁,直接返回
        if(instance == null){
            synchronized (Singleton.class){
                // 第二次判断是否为null
                if(instance == null){
                     instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

4、静态内部类方式

推荐使用

JVM在加载外部类的过程中不会加载静态内部类,只有内部类的属性/方法被调用时才会被加载

public class Singleton{
    private Singleton(){}
   // 定义一个静态内部类
    private static class SingletonHolder{
        // 在内部类中申明并定义外部类的对象,防止外部修改对象加一个final
        private static final Singleton INSTANCE = new Singleton();
        
    }
    // 公共访问方式
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

静态内部类单例模式是开源项目中常用的一种单例模式,不需要加锁也可以保证多线程下的安全

5、枚举方式

枚举方式是极力推荐的单例实现方式,因为枚举类型是线程安全的,并且只会加装一次,是所有单例实现中唯一一种不会被破坏的单例实现模式

推荐使用

public enum Singleton{
    INSTANCE;
}

单例模式存在的问题

破坏单例模式:

单例类可以创建多个对象,枚举方式除外,分别是序列化和反射。

1、序列化反序列化 Singleton类实现Serializable接口

2、反射方式:

public class Client{
    public static void main(String[] args) throws Exception{
        // 获取Singleton的字节码对象
        Class clazz = Singleton.class;
        // 获取无参构造方法
        Constructor cons = clazz.getDeclaredConstructor();
        // 取消访问检查
        cons.setAccessible(true);
        Singleton s1 = (Singleton)cons.newInstance();
        Singleton s2 = (Singleton)cons.newInstance();
        System.out.println(s1 == s2); // false;
    }
}

解决方法

1、序列化反序列化可以添加一个readResolve()方法

public class Singleton{
    private Singleton(){}
   // 定义一个静态内部类
    private static class SingletonHolder{
        // 在内部类中申明并定义外部类的对象,防止外部修改对象加一个final
        private static final Singleton INSTANCE = new Singleton();
        
    }
    // 公共访问方式
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
    
    // 当进行反序列化时,会自动调用该方法,将调用方法的返回值直接返回
    public Object readResolve(){
        return SingletonHolder.INSTANCE;
    }
}

2、解决反射方式

public class Singleton{
    private static boolean flag = false;
    private Singleton(){
        synchronized (Singleton.class){
        // 判断flag的值是否是true,如果是true,说明非第一次访问,直接抛异常,如果是false说明第一次访问
            if(flag) {
                throw new RuntimeException("不能创建多个对象");
            }
            // 将flag的值设置为true
            flag = true;
        }
    }
   // 定义一个静态内部类
    private static class SingletonHolder{
        // 在内部类中申明并定义外部类的对象,防止外部修改对象加一个final
        private static final Singleton INSTANCE = new Singleton();
        
    }
    // 公共访问方式
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

JDK 中Runtime类使用了饿汉式


工厂模式

1、简单工厂模式

简单工厂模式不是一种模式,更像是一种编程习惯

缺点:违背了开闭原则,工厂和产品耦合

2、工厂方法模式

抽象工厂 AbstractFactory:提供创建产品的接口,调用者通过访问它访问具体工厂的工厂方法来创建产品

具体工厂 ConcretteFactory:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

抽象产品 Product:定义了产品的规范,描述了产品的主要特性和功能。

具体产品 ConcreteProduct:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂一一对应

缺点:每增加一个新的产品都需要增加一个具体的产品类和具体工厂类,增加系统复杂度,类太多会造成类爆炸

3、抽象工厂模式

抽象工厂 AbstractFactory:提供创建产品的接口,包含多个创建产品的方法,可以创建不同等级的产品。

具体工厂 ConcretteFactory:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

抽象产品 Product:定义了产品的规范,描述了产品的主要特性和功能,有多个抽象的产品

具体产品 ConcreteProduct:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂多对一的关系

缺点:每增加一个新的产品时候,所有工厂类都需要修改

模式扩展

简单工厂+配置文件解除工厂对象和产品对象的耦合,spring框架原理

JDK源码中Collection.iterator方法用了工厂模式


原型模式

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象

抽象原型类:规定了具体原型对象必须实现的clone()方法

具体原型类:实现抽象原型类的clone()方法,可以被复制的对象

访问类:使用具体原型类中的clone()方法来复制新的对象

浅克隆:创建一个对象,新对象的属性和原来对象完全相同,对于非基本类型属性,任然指向原有属性所指向的对象的内存地址

深拷贝:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址

java中Object类clone()方法是浅拷贝,Cloneable接口就是抽象原型类

具体原型类

public class Realizetype implements Cloneable{
    @Override
    public Realizetype clone() throws CloneNotSupportedException{
        return (Realizetype)super.clone();
    }
}

访问类

public class client{
    public static void main(String[] args){
        Realizetype realizetype = new Realizetype();
        Realizetype clone = realizetype.clone();
        System.out.println(realizetype == clone); // false;
    }
}

深拷贝

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/353746.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号