3

每天5分钟-创建型模式(二)

 2 years ago
source link: https://segmentfault.com/a/1190000039978380
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

这篇就是设计模式的最后一篇文章了,写的非常简洁,基本上是通过例子来解释模式。虽然并没有很深挖,但是如果能帮到你们理解到是什么这个地步我觉得就够了。

下一个系列的话,大概率是spring全家桶这方面的,也有可能是其它方面的。

单例模式应该算是最常用的设计模式了叭,著名的双重校验也是单例模式的一种实现。所谓单例模式就是用来保证一个对象只能创建一个实例,除此之外,它还提供了对实例的全局访问方式。

单例模式UML类图

单例模式饿汉式

所谓饿汉式,人饿了看到啥都想吃。同样,不管需不需要这个实例,反正我都先给你创建好。

普通实现

public class SingletonHungry {
    
    //在类加载的时候就已经创建了唯一的实例
    private static final SingletonHungry instance = new SingletonHungry();
    
    //保证外部不能调用构造函数
    private SingletonHungry() {
    }

    //外部调用这个方法,就返回实例
    public static SingletonHungry getInstance() {
        return instance;
    }
    
    //类中其它方法,尽量是static
    public static void func(){}
    
}

静态代码块

public class SingletonHungryStatic {
    //其实就是把new的部分移到了静态代码块中
    private static SingletonHungryStatic instance = null;
    static {
        instance = new SingletonHungryStatic();
    }

    private SingletonHungryStatic() {
    }

    public static SingletonHungryStatic getInstance() {
        return instance;
    }

    //类中其它方法,尽量是static
    public static void func(){}
}

单例模式懒汉式

所谓懒汉,就是要不是有人催促,就不肯去劳动。同理,只有你找我要这个是,才创建出来。

普通实现

public class SingletonLazy {
    //volatile之前已经讲过,防止指令的重排序,这个volatile是不能省略的
    private static volatile SingletonLazy instance = null;
    private SingletonLazy(){}

    public static SingletonLazy getInstance() throws Exception {

        if(instance == null) {
            synchronized (SingletonLazy.class) {
                if(instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }
}

静态内部类

public class SingletonLazyStatic {
    
    /**
     * 静态内部类注意事项
     *  1. 类加载的时,静态内部类不会随着加载
     *  2. 静态内部类只会初始化一次
     *  3. 线程安全的
     */
    
    private static class StaticClassInstance{
        private static final SingletonLazyStatic INSTACE = new SingletonLazyStatic();
    }
    private SingletonLazyStatic() {
    }
    
    public static SingletonLazyStatic getInstance() {
        return StaticClassInstance.INSTACE;
    }
}

其实还有一种更为优雅的实现方式,那就是使用枚举,不过之前看那些文章好像都说什么少用,所以本文就不粘出来给各位增加学习成本了。

Client

public class Client {
    public static void main(String[] args) throws Exception {
//        hungry();
//        hungryStatic();
//        lazy();
        lazyStatic();
    }

    public static void lazyStatic() {
        SingletonLazyStatic instance = SingletonLazyStatic.getInstance();
        SingletonLazyStatic instance1 = SingletonLazyStatic.getInstance();
        System.out.println(instance);
        System.out.println(instance1);
    }
    
    //下面3中和上面实现是类似的,只需要更换类名
    public static void lazy() throws Exception {}

    public static void hungry() {}

    public static void hungryStatic() {}

}

原型模式听起来高大上,其实就是一种克隆对象的方法。

说到克隆不得不简单说下浅拷贝和深拷贝,浅拷贝就是指两个指针指向了同一个对象,原对象和拷贝对象只要有一个修改,另外一个也随着修改。深拷贝是指,重新创建了一个和原对象一模一样内容的拷贝对象,两者是独立的。基本数据类型是不参与拷贝过程的

Prototype: 抽象原型类,声明了clone方法的接口或者基类,其中clone方法必须由派生对象实现。

Concrete Prototype: 具体实现类,主要是用于实现或扩展clone方法的类。

原型模式UML类图

Prototype

public abstract class PrototypePhone implements Cloneable {
    private String cpu;
    private int price;

    @Override
    public  Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    //省略构造函数,get,set方法

}

Concrete Prototype

public class ConcretePrototypeOnePlus extends PrototypePhone {
    public ConcretePrototypeOnePlus(String cpu, int price) {
        super(cpu, price);
        System.out.println("调用了构造函数");
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Client

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        PrototypePhone phone = new ConcretePrototypeOnePlus("865", 3999);
        System.out.println("原型:" + phone);
        for (int i = 0; i < 100; i++) {
            System.out.println("生产第" + (i + 1) + "台手机:" + phone.clone());
        }
    }
}

运行的话就会发现构建的手机只通过了一次构造函数,其它的使用phone.clone() 也能同样构造出手机实例对象。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK