【设计模式】创建者模式

创建者模式,顾名思义,就是提供友好的创建对象的方式 ,对象都是 new 出来的,但是在一些情况下,这种方式不是很友好,首先,它不够直观,其次,在一些情况下,这样创建的对象不满足要求。 —— 比如 : 当我们需要创建单例的对象,那我们就不能每次用的时候就重新 new, 这样很明显是不合理的 。

一、工厂模式

引入工厂类的原因 : 是因为我们需要两个或者两个以上的工厂生产对象,假如我们就需要一个对象的工厂,那就没必要引入工厂类了 。

1. 简单工厂模式

就一个工厂,它具有不同的方法,生产出不同的产品 。
【设计模式】创建者模式_第1张图片

2. 工厂模式

我们需要两个及以上的工厂,所以抽象出一个工厂接口,其他工厂实现类实现这个抽象接口,重写创建方法 。

【设计模式】创建者模式_第2张图片

3. 抽象工厂模式

涉及到产品族问题 , 调用的时候先选择工厂,再调用其方法,生成相应的产品。

【设计模式】创建者模式_第3张图片

举个 : 工厂模式在 Spring 框架中的使用

Spring 框架通过反射机制实现工厂模式,从而降低了程序的耦合程度 。具体实现思路为 : 读取配置文件中相关值, 然后通过反射 Class.forName 得到该值对应的类,再通过 newInstance() 获取该类的实例返回 。

我们调用时只需要 : Factory.getXXX("我们定义在配置文件中的 Bean 名称")

二、单例模式

1. 饿汉式实现

私有构造方法 + 创建静态实例

public class Singleton {
    // 私有构造方法
    private Singleton() {};
    // 创建私有静态实例
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
}

缺点 : 不想用 Singleton 实例时,它也生成了,因为是 static 的, 这个类被第一次使用时就会被生成 。

2. 饱汉式实现 —— 双重检查机制原理

私有构造方法 + volatile 修饰 + 双重判空,加锁

public class Singleton {
    // 私有构造方法
    private Singleton() {}
    // valitale 修饰
    private static volatile Singleton instance = null;

    public static Singleton getInstance() {
    	// 双重检查是否为 null
        if (instance == null) {
            // 加锁
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  1. 为什么要在实例化时加 synchronized 锁, 不是已经用 volatile 关键字修饰了吗 ?

因为 volatile 只可以保证变量的可见性 和 防止实例化时指令重排 ,它不能保证操作的原子性 。我们要求只能有一个线程去实例化,不能一堆线程一起进去实例化 。

  1. 不是已经有 synchronized 锁了吗,为什么还要 volatile 关键字修饰 ?

因为我们得保证 一个线程实例化 Singleton 后,其他线程可见,直接返回就行,所以我们需要 volatile 去保证 Singleton 在多个线程中的可见性 , 不被 JVM 缓存。

除此之外,它也通过防止对象创建时的指令重排,而使得线程安全 。

什么是指令重排 ?
创建对象时,先分配内存空间,然后实例指向该空间地址,然后才初始化 。
正常情况应该是, 分配内存空间 — 初始化 — 指向该空间地址

如果不用 volatile 修饰, 发生指令重排时, 创建对象的线程只是指向了空间地址,但是还没初始化,但是因为已经指向地址了,下一个线程在第一重 null 检查时,判断为非 null,直接返回了,但是返回的实例还没初始化 。—— 这是线程不安全的,所以需要 volatile 。

3. 嵌套类实现

利用嵌套类可以 访问外部类 的属性和方法 。在嵌套类中实例化 Singleton 。

public class Singleton {

    private Singleton() {}
    // 利用嵌套类可以访问外部类的属性和方法
    private static class Holder {
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.instance;
    }
}

4. 枚举实现 *

据说被谷歌大佬作为实现单例的最佳实践 —— 这个还简单、还安全 , 那我们学上面那些干啥 ???

public enum Singleton {
     INSTANCE;
}

三、建造者模式

链式调用方法,实现对象的创建 。 —— 为什么优于 new ?

首先,一个设计模式是最佳实践是相对其使用场景说的。 建造者模式适用于要创建的对象非常复杂的情况,构造者模式让这个复杂类的装配变得按部就班又直观。

举个栗子

MyBatis 中读取配置文件构建配置类,这个配置类超级大 。所以使用了建造者模式,把这个复杂类的构建拆分成了好多 builder,根据传入的参数的不同进行创建 。

四、原型模式

对于原型模式,首先我们需要记住的就是实现 Cloneable 接口,并且重写 clone 方法 。(注意深浅克隆的区别)

其实,按照我对原型模式的理解,就是新建了一个模板。然后,我们不断去克隆这个模版,更改模版中的一些值。

你可能感兴趣的:(设计模式,单例模式,java)