创建模式---单例模式和原型模式

单例模式

单例模式即只有一个对象的类模式
使用简单工厂的方式实现:
最常使用的单利模式,懒加载模式:

public class Product {
    public static Product product;

    private Product() {
    }

    public static Product getInstance() {
        if (null == product) {
            return new Product();
        } else {
            return product;
        }
    }

    public static void main(String[] args) {
        Product product = Product.getInstance();
    }
}

多线程下的单利模式

类加载模式,可以保证线程安全,因为在类加载过程中jvm会锁定.class对象

public class Product {
    public static Product product = new Product();

    private Product() {
    }

    public static Product getInstance() {
        return product;
    }

    public static void main(String[] args) {
        Product product = Product.getInstance();
    }
}

双重检测下的volatile模式

public class Product {
    //注意此处一定要使用volatile关键字,volatile关键字可以禁止指令重排,因为new Product()不是一个原子操作
    public static volatile Product product;

    private Product() {
    }

    public static Product getInstance() {
        if (null == product) {
            synchronized (Product.class) {
                if (null == product) {// 第二重检测
                    product = new Product();
                }
            }
        }
        return product;
    }

    public static void main(String[] args) {
        Product product = Product.getInstance();
    }
}

其中new Product()分为三步:
内存分配、初始化、返回对象在堆上的引用
指令重排后可能为:
内存分配、返回对象在堆上的引用、初始化
返回对象在堆上的引用之后对象就不为null了,不管是否初始化,所以指令重排为第二种方式的时候就会产生返回未初始化对象的情况
具体如下:
线程1执行到返回对象引用
线程2检测对象是否为null,发现不为null,直接返回对象,这个时候线程1还没初始化对象,导致返回未初始化的对象

原型模式

如果说单例模式是一个类指创建一个对象,那原型就是和new差不错,可以创建多个对象,不过和new的区别在于它效率很高,直接使用拷贝二进制码的方式,创建大量对象,可以考虑使用原型
实战中的原型模式要不直接使用spring原型,要不直接使用java原型clone方法
java中的原型:

浅拷贝

只能拷贝基本类型(包含String),无法拷贝引用类型

//必须实现Cloneable接口,此接口只是一个声明接口
public class Product implements Cloneable {
    private Integer id;
    private String name;

    public Product(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    //此处省略get,set方法
    @Override
    protected Product clone() throws CloneNotSupportedException {
        return (Product) super.clone();
    }

    public static void main(String[] args) {
        Product p1 = new Product(1, "name1");
        System.out.println(p1 + "    id:" + p1.getId() + ",name:" + p1.getName());
        try {
            Product p2 = p1.clone();
            System.out.println(p2 + "    id:" + p2.getId() + ",name:" + p2.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

结果:

Product@6996db8    id:1,name:name1
Product@1963006a    id:1,name:name1
深拷贝

所有引用类型都实现Cloneable并重写clone方法,然后一层一层拷贝下去即深拷贝(包含集合和任意类)

//必须实现Cloneable接口,此接口只是一个声明接口
public class Product implements Cloneable {
    private Integer id;
    private String name;
    private OtherProduct otherProduct;

    public Product(Integer id, String name, OtherProduct otherProduct) {
        this.id = id;
        this.name = name;
        this.otherProduct = otherProduct;
    }
    //此处省略get,set方法
    @Override
    protected Product clone() throws CloneNotSupportedException {
        Product clone = (Product) super.clone();
        //此处拷贝引用类型,说白了就是所有引用类型都实现Cloneable并重写clone方法,然后一层一层拷贝下去即深拷贝
        clone.setOtherProduct(otherProduct.clone());
        return clone;
    }

    public static void main(String[] args) {
        Product p1 = new Product(1, "name1", new OtherProduct());
        System.out.println(
                p1 + "    id:" + p1.getId() + ",name:" + p1.getName() + ",otherProduct:" + p1.getOtherProduct());
        try {
            Product p2 = p1.clone();
            System.out.println(
                    p2 + "    id:" + p2.getId() + ",name:" + p2.getName() + ",otherProduct:" + p2.getOtherProduct());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

结果:

Product@1963006a    id:1,name:name1,otherProduct:OtherProduct@7fbe847c
Product@41975e01    id:1,name:name1,otherProduct:OtherProduct@c2e1f26

猜你喜欢

转载自blog.csdn.net/weixin_43060721/article/details/82154330