Java设计模式之 单例模式

Java设计模式 - 单例模式

 

单例模式使用场景:

单例模式保证仅有一个实例,并提供一个访问它的全局访问点.当系统需要某个类只能有一个实例时,就可以采用单例模式.

 

源码下载地址:

https://github.com/godlikecheng/singleton_model

单例模式的实现方式:

1.直接实例化

package singleton_model;

/**
 * 单例模式 - 直接实例化
 * @author 张宜成
 */
public class Singleton_01 {
	
	// 构造方法私有化
	private Singleton_01 () {
		
	}
	
	// 直接产生单例模式
	private static final Singleton_01 single = new Singleton_01();
	public static Singleton_01 getinstance () {
		return single;
	}
	
}

2.延迟实例化

package singleton_model;

/**
 * 单例模式 - 延迟实例化
 * @author 张宜成
 */
public class Singleton_02 {
	
	// 构造方法私有化
	private Singleton_02 () {
		
	}
	
	private static Singleton_02 single = null;
	/*
	 * 本方法是通过双重锁部分同步机制获得单例对象的.
	 * 因为代码中有两行相同的语句if(single == null),故叫做双重锁.
	 */
	public static Singleton_02 getInstance () {
		if (single == null) {
			synchronized (Singleton_02.class) {
				if (single == null) {
					single = new Singleton_02();
				}
			}
		}
		return single;
	}
	
}

3.静态内部类

package singleton_model;

/**
 * 单例模式 - 静态内部类 -> 利用静态内部类生成的单例对象时更优的
 * @author 张宜成
 */
public class Singleton_03 {
	
	// 静态内部类
	private static class My {
		private static final Singleton_03 single = new Singleton_03();
	}
	
	private Singleton_03 () {
		System.err.println("This is new instance!!!");  // 做测试使用
	}
	
	public static final Singleton_03 getInstance () {
		return My.single;
	}
}

静态内部类 - 测试类:

package singleton_model;

/**
 * 单例模式 - 静态内部类 -> 利用静态内部类生成的单例对象时更优的
 * @author 张宜成
 */
public class Singleton_03 {
	
	// 静态内部类
	private static class My {
		private static final Singleton_03 single = new Singleton_03();
	}
	
	private Singleton_03 () {
		System.err.println("This is new instance!!!");  // 做测试使用
	}
	
	public static final Singleton_03 getInstance () {
		return My.single;
	}
}

运行效果:

应用案例:

1.编制日志类.一般来说,应用程序都有日志文件,记录一些执行信息,该功能利用单例对象来实现是比较恰当的.本案例实现最基本的功能,包括:记录时间及相关内容字符串,其代码如下所示.

package singleton_model;

import java.io.*;
import java.util.*;

/**
 * 编制日志类,一般来说,应用程序都有日志文件,记录一些执行信息,该功能利用单例对象来实现是比较恰当的.
 * 本例实现最基本的功能,包括:记录时间及相关内容字符串.
 * @author 张宜成
 */
public class FileLogger {

	private String path = "f:/";
	private FileOutputStream out;
	
	private FileLogger() throws Exception {
		System.out.println("This is new instance !");
	}
	
	// 公有写入方法,供测试类调用
	public void write(String msg) {
		try {
			Calendar c = Calendar.getInstance();
			int y = c.get(Calendar.YEAR);
			int m = c.get(Calendar.MONTH);
			int d = c.get(Calendar.DAY_OF_MONTH);
			int hh = c.get(Calendar.HOUR);
			int mm = c.get(Calendar.MINUTE);
			int ss = c.get(Calendar.SECOND);
			String strTime = "";
//			strTime = strTime.format("time:%d-%02d-%02d %02d:%02d:%02d\r\n", y,m,d,hh,mm,ss);
			String strContent = "content:\r\n" + msg + "\r\n";
			byte buf[] = strTime.getBytes("gbk");
			out.write(buf);
			out.flush();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	// 公有关闭方法,供测试类使用
	public void close() {
		try {
			out.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	// 静态内部类
	/*
	 * 按照
	 * private static FileLogger getInstance(){
	 * 		private static final FileLogger log = new FileLogger();		
	 * }
	 * 是错误的,他需要处理流的异常,用try..catch代码块来处理
	 */
	private static class My {
		static FileLogger log;
		static {
			try {
				log = new FileLogger();
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	// 提供访问内部类的公有方法
	public static FileLogger getInstance(){
		return My.log;
	}
}

日志类 - 测试类

package singleton_model;

/**
 * 一个简单的应用该日志类的测试代码如下所示.
 * @author 张宜成
 */
public class FileLogger_Test {

	public static void main(String[] args) {
		FileLogger obj = FileLogger.getInstance();  // 获得日志 的单例对象
		obj.write("hello");
		obj.write("你好!");
		obj.close();
	}

}

2.编制配置文件信息单例模式 配置文件是应用程序经常采用的技术,它的内容为整个应用程序所共享,具有唯一性,因此利用单例对象来读取配置文件是可取的.假设关于数据库文件的信息图下如,并存放到f:/config.txt

url=jdbc:mysql://localhost:3306/mydb
username=root
password=123456

读取配置文件单例类代码如下所示.

package singleton_model;

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * 单例模式 - 编制配置文件文件信息单例信息类
 * 
 * @author 张宜成
 */
public class MyConfig {

	private static Map<String, String> map = new HashMap(); // 保持配置文件键值对

	private MyConfig() {
		try {
			FileInputStream in = new FileInputStream("f:/config.txt");
			Properties p = new Properties();
			p.load(in);
			Set<Object> keys = p.keySet();
			Iterator it = keys.iterator();
			while (it.hasNext()) {
				String key = (String) it.next();
				String value = p.getProperty(key);
				map.put(key, value);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private static class My {
		private static final MyConfig single = new MyConfig();
	}
	
	public static MyConfig getInstance () {
		return My.single;
	}
	
	public String getInfo(String key) {
		return map.get(key);
	}

}

读取配置文件单例类 - 测试类

package singleton_model;
/**
 * 单例模式 - 读取配置文件信息案例 - 测试类
 * @author 张宜成
 */
public class MyConfig_Test {

	public static void main(String[] args) {
		MyConfig mc = MyConfig.getInstance();  // 获得单例对象
		String url = mc.getInfo("url");  // 获取数据库的连接
		String user = mc.getInfo("username");  // 获取用户名
		String pwd = mc.getInfo("password");  // 获取密码
		System.out.println("url = " + url);
		System.out.println("user = " + user);
		System.out.println("pwd = " + pwd);
	}

}

运行效果:  将config.txt文件中的数据读取到了控制台

3.应用服务器单例技术仿真. 本示例利用java应用程序首先简单的仿真这一过程,即根据URL查找出对应的name值,再根据name值获得相应的运行类.具体功能是可激素那两个整数的加或减结果.所需要的代码如下所示.

定义接口IFunc

package singleton_model;

/**
 * 单例模式 - 应用服务器单例技术仿真
 * 本案例利用java应用程序首先简单的仿真这一过程,即根据URL查找出对应的name值,
 * 再根据name值获得响应的运行类.具体功能是可计算证书的加或减结果.
 * @author 张宜成
 */
public interface IFunc {
	public int service(int one,int two);
}

定义功能类PlusFunc

package singleton_model;

/**
 * 单例模式 - 应用服务器单例技术仿真
 * @author 张宜成
 */
public class PlusFunc implements IFunc {

	// 定义无参构造方法
	private PlusFunc(){
		
	}
	
	// 定义匿名类
	private static class My {
		private static final PlusFunc single = new PlusFunc();
	}
	
	// 定义公有方法,让调用内部类中的方法
	public static PlusFunc getInstance () {
		// 调用内部类的方法,可以直接使用类名.方法名而无需实例化
		return My.single;
	}
	
	// 实现接口中的方法 实现两个数的相加
	public int service(int one, int two) {
		return one + two;
	}
	
}

定义功能类 MinusFunc

package singleton_model;

/**
 * 单例模式 - 应用服务器单例技术仿真
 * 本案例利用java应用程序首先简单的仿真这一过程,即根据URL查找出对应的name值,
 * 再根据name值获得响应的运行类.具体功能是可计算证书的加或减结果.
 * @author 张宜成
 */
public class PlusFunc implements IFunc {

	// 定义无参构造方法
	private PlusFunc(){
		
	}
	
	// 定义匿名类
	private static class My {
		private static final PlusFunc single = new PlusFunc();
	}
	
	// 定义公有方法,让调用内部类中的方法
	public static PlusFunc getInstance () {
		// 调用内部类的方法,可以直接使用类名.方法名而无需实例化
		return My.single;
	}
	
	// 实现接口中的方法 实现两个数的相加
	public int service(int one, int two) {
		return one + two;
	}
	
}

测试类

package singleton_model;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * 单例模式 - 应用服务器单例技术仿真 - 测试类
 * @author 张宜成
 */
public class IFunc_Test {
	public static void main(String[] args) {
		IFunc obj = PlusFunc.getInstance();  // 获得加单例对象
		IFunc obj2 = MinusFunc.getInstance();  // 获得减单例对象
		
		Map<String,Object> mapNameToObj = new HashMap();
		mapNameToObj.put("plus", obj); // 将单例对象加入map映射中
		mapNameToObj.put("minus", obj2); // name与类关联
		
		Map<String,String> mapURLToName = new HashMap();
		mapURLToName.put("plusurl", "plus");  // URL与name关联
		mapURLToName.put("minusurl", "minus"); 
		
		Scanner s = new Scanner(System.in);
		while(true) {
			String url = s.nextLine();  // 输入url,形如:plusurl 3 5
			String unit[] = url.split(" ");
			String name = mapURLToName.get(unit[0]);
			IFunc iobj = (IFunc)mapNameToObj.get(name);
			int result = iobj.service(Integer.parseInt(unit[1]), Integer.parseInt(unit[2]));
			System.out.println("result is :" + result);
		}
		
	}
}

运行结果


下一篇: Java设计模式之 工厂模式

猜你喜欢

转载自blog.csdn.net/qq_40820862/article/details/82584718