设计模式-单例模式

一、单例模式核心思想

单例模式是一种特殊的工厂方法模式,它适合于一个类只有一个实例的情况,比如窗口管理器打印缓冲池和文件系统。典型的情况是,那些对象的实例能够被整个软件系统的不同对象访问,因此需要一个全局的访问指针,这便是众所周知的单例模式的应用。当然这只有在不再需要任何多于一个的实例的情况下出现。

通过单例模式你可以:

  • 确保一个类只有一个实例被建立。
  • 提供了一个对对象的全局访问指针。
  • 在不影响单例类的客户端的情况下允许将来有多个实例。

单例模式的实例在全局中有且只有一个,并且该实例必须由自身创建,不能够被克隆。为了满足这些要求,一个标准的单例模式需要包含如下4个要素:

(1) 拥有一个私有的静态实例,该实例禁止外部访问。

(2) 拥有私有的默认构造函数,防止使用构造函数进行实例化。

(3) 拥有一个静态工厂方法,并且必须是同步的,防止多线程环境同时执行。

(4) 重写clone0)函数,并返回当前实例对象,默认的clone()函数会创建新的实例。

根据以上4点要求,完成的标准单例模式代码如下程序所示:

java 复制代码
package creation.singleton;

public class SingletonFactory {

	//(1)私有的防止外部引用
	private static SingletonFactory _instance = null;
	
	//(2)私有的默认构造函数,防止使用构造函数进行实例化
	private SingletonFactory(){}
	
	//(3)单例静态工厂方法,同步防止多线程环境同时执行
	synchronized public static SingletonFactory getInstance(){
		if( _instance == null){
			_instance = new SingletonFactory();
		}
		return _instance;
	}

	//(4)重写该函数,默认的cloneO函数会创建新的实例
	public SingletonFactory clone(){
		return getInstance();
	}
}

以上单例模式的代码中的各项缺一不可,读者可以作为单例模式的标准模板使用,在后面的示例中我们也将使用该模板进行开发。

二、何时使用单例模式

使用单例模式有一个前提条件:就是在一个系统中某一个类的实例必须只有一个,如果可以有多个实例存在,就不能够使用单例模式。以上的说法比较抽象,具体的可以应用在如下场景:

  • 系统的全局变量、存储区域。
  • 系统的全局配置文件。
  • 系统的全局操作函数。

由此可见,只要希望在全局使用一个统一的对象,就可以使用单例模式。

三、属性文件加载工厂实例

根据以上的场景,我们举例说明。以属性文件为例,在一个系统中,通常需要配置全局的属性文件,例如用户名和密码文件,如下程序所示:

属性文件user.properties

java 复制代码
admin=123
liuzhongbing=123
guest=123

为了在系统中使用该属性文件中定义的用户名和密码,可以根据以上的单例模式模板文件SingletonFactory.java创建一个工厂类,其中定义一个私有变量 properties,用来在系统启动时将文件读取数据存储在该变量中,并提供一个按照用户名查找密码的函数getConfigO。完整的代码如下程序所示:

属性文件工厂PropertiesFactory.java

java 复制代码
import java.util.Properties;
import java.io.FilelnputStream;

public class PropertiesFactory {

	//(1)私有的防止外部引用
	private static PropertiesFactory instance = null;
	private Properties properties = new Properties();
	
	//(2)私有的默认构造函数,防止使用构造函数进行实例化
	private PropertiesFactory(){
		try {
			properties.load(new
			FileInputStream("sre/creation/singleton/user.properties'));
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	//(3)单例静态工厂方法,同步防止多线程环境同时执行
	public static synchronized PropertiesFactory getInstance(){
		if( instance == null){
			instance = new PropertiesFactory();
			return instance;
		}
	}

	//(4)重写该函数,默认的clone()函数会创建新的实例
	public PropertiesFactory clone(){
		return getInstance();
	}
	
	public String getConfg(String key){
		return properties.getProperty(key);
	}


}

编写测试类来读取其中的密码,如下程序所示:

测试类PropertiesFactoryTest.java

java 复制代码
package creation.singleton;


publie class PropertiesFactoryTest {
	public static void main(String[] args){
		PropertiesFactory factory= PropertiesFactory.getInstance():
		String pwdl = factory.getConfig("admin");
		System.out.println(pwdl);
	}
}

运行该程序即会输出密码:123。

四、Java中的应用--日历单例类 Calendar

java 复制代码
package java.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io .ObjectOutputStream;
import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import sun.util.BuddhistCalendar;
import sun.util.calendar.Zonelnfo;
import sun.util.resources.LocaleData;
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>{

	protected Calendar(){
		this(TimeZone.getDefaultRef(), Locale.getDefault());
		sharedZone = true;
	}
	
	protected Calendar(TimeZone zone, Locale aLocale){
		fields = new int[FIELD_COUNT];
		isSet = new boolean[FIELD_COUNT];
		stamp = new int[FIELD_COUNT];
		this.zone = zone;
		setWeekCountData(aLocale);
	}
	
	public static Calendar getInstance() {
		Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault());
		cal.sharedZone = true;
		return cal;
	}
	
	public static Calendar getInstance(TimeZone zone) {
		return createCalendar(zone, Locale.getDefault());
	}
	
	public statie Calendar getInstance(Loeale aLocale) {
		Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale)
		cal.sharedZone = true;
		return cal;
	}
	
	public static Calendar getInstance(TimeZone zone, Locale aLocale) {
		return createCalendar(zone, aLocale);
	}

}

从代码可以看出,该单例类的应用并不是严格遵守单例模式的四项规则。所以,在实际的开发中,可以根据实际的需要来自由运用。

相关推荐
刷帅耍帅2 小时前
设计模式-桥接模式
设计模式·桥接模式
MinBadGuy3 小时前
【GeekBand】C++设计模式笔记5_Observer_观察者模式
c++·设计模式
刷帅耍帅3 小时前
设计模式-生成器模式/建造者模式Builder
设计模式·建造者模式
蜡笔小新..1 天前
【设计模式】软件设计原则——开闭原则&里氏替换&单一职责
java·设计模式·开闭原则·单一职责原则
性感博主在线瞎搞1 天前
【面向对象】设计模式概念和分类
设计模式·面向对象·中级软件设计师·设计方法
lucifer3111 天前
JavaScript 中的组合模式(十)
javascript·设计模式
lucifer3111 天前
JavaScript 中的装饰器模式(十一)
javascript·设计模式
蜡笔小新..1 天前
【设计模式】软件设计原则——依赖倒置&合成复用
设计模式·依赖倒置原则·合成复用原则
刷帅耍帅1 天前
设计模式-代理模式
设计模式·代理模式
神的孩子都在歌唱2 天前
行为设计模式 -观察者模式- JAVA
java·观察者模式·设计模式