一、单例模式概述
单例模式的定义:又叫单件模式,确保一个类只有一个实例,并提供一个全局访问点。(对象创建型)
- 要点:
- 1.某个类只能有一个实例;
- 2.必须自行创建这个实例;
- 3.必须自行向整个系统提供这个实例。
- 单例模式的优缺点:
- 优点:
- 1.提供了对唯一实例的受控访问
- 2.可以节约系统资源,提高系统的性能
- 3.允许可变数目的实例(多例类)
- 缺点:
- 1. 全局变量:单例模式实质上就是全局变量。全局变量可能会被误修改,而且调试困难;
- 2. 并发问题:在多线程环境下,如果没有正确地处理,可能会导致多个实例被创建;
- 3.单例类通常承担了太多的职责,因为为了让某个类的对象共享,就把这个类设计成了单例类,这违反了单一职责原则.
- 优点:
- 适用环境:
- 1.系统只需要一个实例对象,或者因为资源消耗太大而只允许创建一个对象
- 2.客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例
- 饿汉式单例类与懒汉式单例类的比较
- 饿汉式:
- 1.无需考虑多个线程同时访问的问题;
- 2.调用速度和反应时间优于懒汉式单例;
- 3.资源利用率不及懒汉式单例;
- 4.系统加载时间可能会比较长。
- 懒汉式:
- 1.实现了延迟加载;
- 2.必须处理好多个线程同时访问的问题;
- 3.需要通过双重检查锁定等机制进行控制,将导致系统性能受到一定的影响。
- 饿汉式:
二、代码实现
单例模式只有一个角色:单例角色
2.1 单例角色(LoadBalancer)
//designpatterns.singleton.LoadBalancer.java
package singleton;
import java.util.*;
//负载均衡器类,充当单例角色
public 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);
}
}
2.2 main方法实现单例模式(Client)
//designpatterns.singleton.Client.java
package singleton;
//客户端测试类
public class Client {
public static void main(String args[]) {
//创建4个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");
//模拟客户端请求的分发,如果输出结果全为同一个server,可以将i适当放大,
//例如改为"i < 100"
for (int i = 0; i < 10; i++) {
String server = balancer1.getServer();
System.out.println("分发请求至服务器: " + server);
}
}
}