创建型模式:单态

单态模式可能是23种创建模式种最简单和容易理解的,创建型模式是主要是为了解决对象的创建的方式,单态则是为了保证创建的对象的唯一性。

模式场景与说明

有早期编码经验的开发者一般在N层应用开发中的业务逻辑层和持久层之间会有数据库连接的获取,不管是从缓冲池中获取还是直接连接JDBC,为了避免创建多个示例产生资源的浪费,一般会使用单态模式对创建对象进行控制。实际上除此之外,在类似的池化控制中都可以类似的引入,比如线程池等。此类对象创建一般存在:重(类似数据库连接的获取)、频(使用程度较为频繁)的特点。

实现方式1

单态模式实现非常简单,一般只要把握两个要点,就能快速创建一个单态模式的类:

  • 控制构造函数:私有化构造函数保证无法随意创建对象
  • 统一创建对象:在类中提供对象的构建方法并提供公有方法返回创建的实例(一般为静态函数)

在这里插入图片描述

实现示例

最简单的示例代码如下所示

public class Singleton {
    // use private key word to avoid being used directly
    private Singleton() {}
    private static Singleton instance = new Singleton();

    // use public method to get singleton instance
    public static Singleton getInstance(){
        return instance;
    }
}

调用方式:Singleton.getInstance();

这里稍微修改一下,显示一下输出内容,特意在构建函数里添加sleep,可以在多个终端同时启动,可以验证并行时仍然使用同一个实例(hashcode相同)。

package com.liumiao;
import java.time.LocalDateTime;

public class Singleton {

    // use private key word to avoid being used directly
    private Singleton() {
        System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
    }
    private static Singleton instance = new Singleton();

    // use public method to get singleton instance
    public static Singleton getInstance(){
        System.out.println("get Singleton instance: " + LocalDateTime.now());
        System.out.println(instance.hashCode());
        return instance;
    }
}

测试代码如下

package com.liumiao;

public class TestSingleton extends Thread {
    public void run() {
        Singleton.getInstance();
    }
    public static void main( String[] args )
    {
        TestSingleton thread1 = new TestSingleton ();
        TestSingleton thread2 = new TestSingleton ();

        thread1.start();
        thread2.start();
    }
}

执行结果如下

2020-06-26T05:37:58.555119: Single instance creating begins... 
2020-06-26T05:37:59.583467: Single instance creating ends... 
get Singleton instance: 2020-06-26T05:37:59.583739
140350290
get Singleton instance: 2020-06-26T05:37:59.583756
140350290

实现方式2

由于实现方式1中对于实例的构建在类装载的时候就已经完成,虽然解决了线程的同步,但是即使没有使用到这个实例也会加载,这里修改一下将new的动作移到getInstance中,通过是否为空来判断一下是否需要new进行构建对象,示例代码如下所示:

package com.liumiao;
import java.time.LocalDateTime;

public class Singleton {

    // use private key word to avoid being used directly
    private Singleton() {
        System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
    }
    private static Singleton instance = null;

    // use public method to get singleton instance
    public static Singleton getInstance(){
        System.out.println("get Singleton instance: " + LocalDateTime.now());
        if (null == instance) {
            instance = new Singleton();
        }
        System.out.println(instance.hashCode());
        return instance;
    }
}

使用同样的测试代码,执行结果如下,所示

get Singleton instance: 2020-06-26T05:39:00.137037
get Singleton instance: 2020-06-26T05:39:00.137051
2020-06-26T05:39:00.137567: Single instance creating begins... 
2020-06-26T05:39:00.137614: Single instance creating begins... 
2020-06-26T05:39:01.162630: Single instance creating ends... 
140350290
2020-06-26T05:39:01.162630: Single instance creating ends... 
1253458049

可以看到,单态出现了问题,产生了不同的实例(hashcode不同),因为没有考虑到线程安全的问题

实现方式3

这里简单地使用synchronized来稍作修改, 代码如下

package com.liumiao;
import java.time.LocalDateTime;

public class Singleton {

    // use private key word to avoid being used directly
    private Singleton() {
        System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
    }
    private static Singleton instance = null;

    // use public method to get singleton instance
    public static synchronized Singleton getInstance(){
        System.out.println("get Singleton instance: " + LocalDateTime.now());
        if (null == instance) {
            instance = new Singleton();
        }
        System.out.println(instance.hashCode());
        return instance;
    }
}

使用同样的测试代码执行结果如下

get Singleton instance: 2020-06-26T05:42:13.732276
2020-06-26T05:42:13.732766: Single instance creating begins... 
2020-06-26T05:42:14.758235: Single instance creating ends... 
346203776
get Singleton instance: 2020-06-26T05:42:14.758679
346203776

所以可以看到已经返回了相同的实例了

其他设计模式

猜你喜欢

转载自blog.csdn.net/liumiaocn/article/details/106954160