一、单例模式概述
单例模式的定义:又叫单件模式,确保一个类只有一个实例,并提供一个全局访问点。(对象创建型)
- 要点:
- 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);}}
}