研磨设计模式之单例模式(Singleton)-解决方案

2019-03-07 09:01|来源: 领悟书生

2  解决方案

2.1  单例模式来解决

       用来解决上述问题的一个合理的解决方案就是单例模式。那么什么是单例模式呢?
(1)单例模式定义
       保证一个类仅有一个实例,并提供一个访问它的全局访问点。
(2)应用单例模式来解决的思路
       仔细分析上面的问题,现在一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,也就是可以让类的外部来通过构造方法创建多个实例。换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。
       要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。


2.2  模式结构和说明

单例模式结构见图1所:


图1  单例模式结构图

Singleton:
       负责创建Singleton类自己的唯一实例,并提供一个getInstance的方法,让外部来访问这个类的唯一实例。


2.3  单例模式示例代码

       在Java中,单例模式的实现又分为两种,一种称为懒汉式,一种称为饿汉式,其实就是在具体创建对象实例的处理上,有不同的实现方式。下面分别来看这两种实现方式的代码示例。为何这么写,具体的在后面再讲述。
      (1)懒汉式实现,示例代码如下:

Java代码
  1. /**

  2. * 懒汉式单例实现的示例

  3. */  

  4. public class Singleton {  

  5.    /**

  6.     * 定义一个变量来存储创建好的类实例

  7.     */  

  8.    private static Singleton uniqueInstance = null;  

  9.    /**

  10.     * 私有化构造方法,好在内部控制创建实例的数目

  11.     */  

  12.    private Singleton(){  

  13.        //  

  14.    }  

  15.    /**

  16.     * 定义一个方法来为客户端提供类实例

  17.     * @return 一个Singleton的实例

  18.     */  

  19.    public static synchronized Singleton getInstance(){  

  20.        //判断存储实例的变量是否有值  

  21.        if(uniqueInstance == null){  

  22.            //如果没有,就创建一个类实例,并把值赋值给存储类实例的变量  

  23.            uniqueInstance = new Singleton();  

  24.        }  

  25.        //如果有值,那就直接使用  

  26.        return uniqueInstance;  

  27.    }  

  28.    /**

  29.     * 示意方法,单例可以有自己的操作

  30.     */  

  31.    public void singletonOperation(){  

  32.        //功能处理  

  33.    }  

  34.    /**

  35.     * 示意属性,单例可以有自己的属性

  36.     */  

  37.    private String singletonData;  

  38.    /**

  39.     * 示意方法,让外部通过这些方法来访问属性的值

  40.     * @return 属性的值

  41.     */  

  42.    public String getSingletonData(){  

  43.        return singletonData;  

  44.    }  

  45. }  

(2)饿汉式实现,示例代码如下:

Java代码
  1. /**

  2. * 饿汉式单例实现的示例

  3. */  

  4. public class Singleton {  

  5.    /**

  6.     * 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只会创建一次

  7.     */  

  8.    private static Singleton uniqueInstance = new Singleton();  

  9.    /**

  10.     * 私有化构造方法,好在内部控制创建实例的数目

  11.     */  

  12.    private Singleton(){  

  13.        //  

  14.    }  

  15.    /**

  16.     * 定义一个方法来为客户端提供类实例

  17.     * @return 一个Singleton的实例

  18.     */  

  19.    public static Singleton getInstance(){  

  20.        //直接使用已经创建好的实例  

  21.        return uniqueInstance;  

  22.    }  

  23.      

  24.    /**

  25.     * 示意方法,单例可以有自己的操作

  26.     */  

  27.    public void singletonOperation(){  

  28.        //功能处理  

  29.    }  

  30.    /**

  31.     * 示意属性,单例可以有自己的属性

  32.     */  

  33.    private String singletonData;  

  34.    /**

  35.     * 示意方法,让外部通过这些方法来访问属性的值

  36.     * @return 属性的值

  37.     */  

  38.    public String getSingletonData(){  

  39.        return singletonData;  

  40.    }  

  41. }  

2.4  使用单例模式重写示例

       要使用单例模式来重写示例,由于单例模式有两种实现方式,这里选一种来实现就好了,就选择饿汉式的实现方式来重写示例吧。
       采用饿汉式的实现方式来重写实例的示例代码如下:

Java代码
  1. /**

  2. * 读取应用配置文件,单例实现

  3. */  

  4. public class AppConfig {  

  5.    /**

  6.     * 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只会创建一次

  7.     */  

  8.    private static AppConfig instance = new AppConfig();  

  9.    /**

  10.     * 定义一个方法来为客户端提供AppConfig类的实例

  11.     * @return 一个AppConfig的实例

  12.     */  

  13.    public static AppConfig getInstance(){  

  14.        return instance;  

  15.    }  

  16.      

  17.    /**

  18.     * 用来存放配置文件中参数A的值

  19.     */  

  20.    private String parameterA;  

  21.    /**

  22.     * 用来存放配置文件中参数B的值

  23.     */  

  24.    private String parameterB;  

  25.    public String getParameterA() {  

  26.        return parameterA;  

  27.    }  

  28.    public String getParameterB() {  

  29.        return parameterB;  

  30.    }  

  31.    /**

  32.     * 私有化构造方法

  33.     */  

  34.    private AppConfig(){  

  35.        //调用读取配置文件的方法  

  36.        readConfig();  

  37.    }  

  38.    /**

  39.     * 读取配置文件,把配置文件中的内容读出来设置到属性上

  40.     */  

  41.    private void readConfig(){  

  42.        Properties p = new Properties();  

  43.        InputStream in = null;  

  44.        try {  

  45.            in = AppConfig.class.getResourceAsStream("AppConfig.properties");  

  46.            p.load(in);  

  47.            //把配置文件中的内容读出来设置到属性上  

  48.            this.parameterA = p.getProperty("paramA");  

  49.            this.parameterB = p.getProperty("paramB");  

  50.        } catch (IOException e) {  

  51.            System.out.println("装载配置文件出错了,具体堆栈信息如下:");  

  52.            e.printStackTrace();  

  53.        }finally{  

  54.            try {  

  55.                in.close();  

  56.            } catch (IOException e) {  

  57.                e.printStackTrace();  

  58.            }  

  59.        }  

  60.    }    

  61. }  

当然,测试的客户端也需要相应的变化,示例代码如下:

Java代码
  1. public class Client {  

  2.    public static void main(String[] args) {  

  3.        //创建读取应用配置的对象  

  4.        AppConfig config = AppConfig.getInstance();  

  5.  

  6.        String paramA = config.getParameterA();  

  7.        String paramB = config.getParameterB();  

  8.  

  9.        System.out.println("paramA="+paramA+",paramB="+paramB);  

  10.    }  

  11. }  

去测试看看,是否能满足要求。


本文链接:研磨设计模式之单例模式(Singleton)-解决方案,转自:http://chjavach.iteye.com/blog/721076

相关问答

更多

什么是单例设计模式

java模式之单例模式: 单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。 特点: 1,一个类只能有一个实例 2,自己创建这个实例 3,整个系统都要使用这个实例 例: 在下面的对象图中,有一个"单例对象",而"客户甲"、"客户乙" 和"客户丙"是单例对象的三个客户对象。可以看到,所有的客户对象共享一个单例对象。而且从单例对象到自身的连接线可以看出,单例对象持有对自己的引用。 Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。在很多 ...

一个单例模式。

单例就是只有一个实例. 如果构造方法公开的话 Single instance = new Single(); 这样,你得到一个实例 如果你再 instance = new Single(); 这时instance 就是一个新的实例了. 而 Single s = Single.getInstance(); 你在程序的生命周期内,什么时候调用,都是同一个实例,也就是说,他们的内存是一块.

Java中的单例设计模式(Singleton Design Pattern in Java)

如果你坚持使用惰性实例化,我认为没有解决方案。 您可以在声明instance变量时创建单例对象: class Singleton { private static final instance = new Singleton(); private Singleton() {} // prevent outside construction public static Singleton getInstance() { return instance; / ...

每线程单例模式(Per thread singleton pattern)

您无能为力,因为您基本上需要通过静态方法代理接口方法。 我只能想到以不同方式实现相同功能的两种方法: 如果你正在使用DI框架,你可以摆脱静态Manager并使用一个注入的ManagerHandler实现,它将包含ThreadLocal 。 使用ManagerHandler接口中的方法生成(如'字节码生成')静态ManagerAccess类。 就个人而言,我不认为将静态ManagerAccess类(包含ThreadLocal )作为一个严重的设计问题。 至少只要它保持自己的职责集(访问线程范围的实例 ...

Spring bean单例与单例模式(Spring bean singleton vs singleton pattern)

这取决于。 如果您需要一个实用程序类,它没有依赖关系,并且只提供一堆公共方法,我认为构建您自己的单例很快捷。 但是如果你想构建一个需要注入其他依赖的业务类,并且可能需要定义接口以避免类之间的耦合,我认为Spring(或其他DI框架)比构建自己的更好(更容易)单身。 It depends. If you need an utility class, which has no dependencies and that just provide a bunch of commons methods, ...

单例模式的例子(example for Singleton pattern)

是的,但只有当所有线程访问相同的文件,并且您正在使用自定义实现(而不是java.io.File ,也许是一个包装器) 单例模式是一种设计模式,用于限制类到一个对象的实例化 单身(通常是不好的选择)是在整个程序中只能有一个实例的类。 例如一个SingletonConfigFile可能看起来像这样。 请记住: 它仅用于读取一个文件。 这是有意义的,这是一个配置文件。 如果你的类可以被实例化多次,对于不同的文件,它不是单例。 不要使用此代码 - 它不考虑并发问题,这是一个完全不同的讨论区域。 。 pub ...

自Java 5以来最好的单例模式(The best singleton pattern since Java 5)

是的,枚举都是从Enum类扩展Enum ,它实现了Serializable 。 Yes, Enums are all extended off of the Enum class, which implements Serializable.

使用Singleton设计模式实现解决方案的建议(Suggestions for implementing a solution using Singleton design pattern)

您将无法“自动”将静态调用委派给模块。 即使调用不是静态的,如你所说,Java也不支持多重继承。 选项1: 让您的主Configuration类提供将实例返回到模块的静态方法。 每当您想要读取配置条目时,首先获取模块实例,然后查询条目本身: Configuration.getDatabaseConfiguration().getServerName(); 此方法的优点是,您可以非常清楚地指定了您的配置的哪个部分。 如果您只使用Configuration.getServerName() ,则无法确 ...

C#类库 - 单例设计模式(C# Class Library - Singleton Design Pattern)

它将通过多次调用持久化,但有一点需要注意。 静态变量的范围限定为AppDomain,因此每当IIS工作进程被回收时,存储在静态变量中的任何数据都将丢失。 会话数据也是如此,如果你将它存储在“proc”中。 如果您想要一个仅在HTTP请求期间存在的对象,则可以使用HttpContext.Items属性。 It will be persisted through multiple calls, but there is one caveat. The static variables are scop ...

Spring bean单例和单例模式[复制](Spring bean singleton and singleton pattern [duplicate])

Spring singleton是唯一的ApplicationContext (每个Spring容器)实例。 这意味着如果您创建一个新的ApplicationContext那么即使它是单例,您也会获得该bean的新实例。 然而原始的Java单例表示每个Classloader一个实例。 这意味着单个实例对于特定的类加载器保持相同。 在大多数情况下,这很好,但是假设你需要一个真正的单例,每个JVM的单个实例,那么还有一些额外的工作要做。 请看这个例子https://stackoverflow.com/ ...