单例模式
单例模式概述:为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。
单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
下面我们来模拟实现Windows任务管理器,假设任务管理器的类名为TaskManager,在TaskManager类中包含了大量的成员方法,例如构造函数TaskManager(),显示进程的方法displayProcesses(),显示服务的方法displayServices()等,该类的示意代码如下:
class TaskManager { public TaskManager() {……} //初始化窗口 public void displayProcesses() {……} //显示进程 public void displayServices() {……} //显示服务 …… }
实现Windows任务管理器的唯一性:
class TaskManager { private static TaskManager tm = null; private TaskManager() {……} //初始化窗口 public void displayProcesses() {……} //显示进程 public void displayServices() {……} //显示服务 public static TaskManager getInstance() { if (tm == null) { tm = new TaskManager(); } return tm; } …… }
note:
1.getInstance()方法的修饰符,首先它应该是一个public方法,以便供外界其他对象使用,其次它使用了static关键字,即它是一个静态方法,在类外可以直接通过类名来访问,而无须创建TaskManager对象,事实上在类外也无法创建TaskManager对象,因为构造函数是私有的。
3.3 负载均衡器的设计与实现
将负载均衡器LoadBalancer设计为单例类,其中包含一个存储服务器信息的集合serverList,每次在serverList中随机选择一台服务器来响应客户端的请求,实现代码如下所示:
import java.util.*; //负载均衡器LoadBalancer:单例类,真实环境下该类将非常复杂,包括大量初始化的工作和业务方法,考虑到代码的可读性和易理解性,只列出部分与模式相关的核心代码 class LoadBalancer { //私有静态成员变量,存储唯一实例 private static LoadBalancer instance = null; //服务器集合 private List serverList = null; //私有构造函数 private LoadBalancer() { serverList = new ArrayList(); } //公有静态成员方法,返回唯一实例 public static LoadBalancer getLoadBalancer() { if (instance == null) { instance = new LoadBalancer(); } return instance; } //增加服务器 public void addServer(String server) { serverList.add(server); } //删除服务器 public void removeServer(String server) { serverList.remove(server); } //使用Random类随机获取服务器 public String getServer() { Random random = new Random(); int i = random.nextInt(serverList.size()); return (String)serverList.get(i); } }
编写如下客户端测试代码:
class Client { public static void main(String args[]) { //创建四个LoadBalancer对象 LoadBalancer balancer1,balancer2,balancer3,balancer4; balancer1 = LoadBalancer.getLoadBalancer(); balancer2 = LoadBalancer.getLoadBalancer(); balancer3 = LoadBalancer.getLoadBalancer(); balancer4 = LoadBalancer.getLoadBalancer(); //判断服务器负载均衡器是否相同 if (balancer1 == balancer2 && balancer2 == balancer3 && balancer3 == balancer4) { System.out.println("服务器负载均衡器具有唯一性!"); } //增加服务器 balancer1.addServer("Server 1"); balancer1.addServer("Server 2"); balancer1.addServer("Server 3"); balancer1.addServer("Server 4"); //模拟客户端请求的分发 for (int i = 0; i < 10; i++) { String server = balancer1.getServer(); System.out.println("分发请求至服务器: " + server); } } }
编译并运行程序,输出结果如下:
分发请求至服务器: Server 1 分发请求至服务器: Server 3 分发请求至服务器: Server 4 分发请求至服务器: Server 2 分发请求至服务器: Server 3 分发请求至服务器: Server 2 分发请求至服务器: Server 3 分发请求至服务器: Server 4 分发请求至服务器: Server 4 分发请求至服务器: Server 1
3.4 饿汉式单例与懒汉式单例的讨论