当前位置:   article > 正文

单例模式-确保对象的唯一性_模式层缺少唯一性

模式层缺少唯一性

设计模式学习与总结之单例模式

一、单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,该类称为单例类,它提供全局访问方法。该类属于创建型模式。
在使用计算机时我们会经常看到这样的情况,当打开任务管理器时,无论我们打开多少次,却总是出现一个窗口。这是什么情况呢?
首先任务管理器便是单例模式的一个具体应用。任务管理器是实时动态显示当前计算机运行的进程以及任务。假设用户可以打开多个任务管理器,那将大量消耗计算机的资源,而且,多个窗口中显示的内容会不同,一个显示CPU利用率10%,另一个显示15%,那你说哪个更可信呢?为此必须确保对象的唯一性。

那么单例模式在其中又是扮演什么样的角色呢?
下面用单例模式模拟任务管理器的功能:

/**
单例模式
*/
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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

由以上代码,可以看到,在类外无法创建新的TaskManager对象,但是可以通过TaskManager.getInstance()来访问实例对象。第一次调用getInstance方法时将创建唯一实例,再次调用时将返回第一次创建的实例。
单例模式
实现单例类主要有三步:
1、构造方法私有化(确保外部类不可以通过new关键字创建对象)
2、静态类类型的私有成员变量(私有化是保证不能被外部类访问,静态类型是确保实例化类后的唯一性)
3、公有的静态访问方法(向整个系统提供访问该实例的方法)

二、负载均衡器
负载均衡器负责将并发访问和数据流量分发到服务器集群中的多台设备上进行性并发处理,提高系统的整体处理能力,由于集群中的服务器中要动态删减,且客户端请求需要统一分发,因此需要确保负载均衡器的唯一性。
负载均衡器结构图

//均衡器的设计
class LoadBalance{
    private static LoadBalance instance = null; //私有静态成员变量,存储唯一实例
    private List serverList = null; //服务器集合

    private LoadBalance(){}   //私有的构造方法

    public static LoadBalance getInstance()  //静态成员方法,返回唯一实例
    {
        if(instance==null)
            instance = new LoadBalance();
        return instance;
    }

    public void addServer(String server) //增加服务器
    {
        serverlist.add(server);
    }
    public void removeServer(String server)//删除服务器
    {
        serverList.remove(server);
    }
    public String getServer()
    {
        Random random = new Random();
        int i= random.nextInt(serverList.size());
        return (String)serverList.get(i);
    }
}
public class Client{
    public static void main(String args[])
    {
        LoadBalance lb1= LoadBalance.getInstance(); //虽然创建了三个LoadBalance对象,但实际上是同一个
        LoadBalance lb2= LoadBalance.getInstance();
        LoadBalance lb3= LoadBalance.getInstance();
        if(lb1==lb2&&lb2==lb3)
            System.out.println("该服务器负载均衡器具有唯一性");
        //增加服务器
        lb1.addServer("Server 1");
        lb2.addServer("Server 2");
        lb3.assServer("Server 3");
        lb1.addServer("Server 4");

        for(int i=0;i<10;i++){
            String server= lb1.getServer();
            Syso.out.println("分发请求至服务器"+server);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

三、饿汉式单例和懒汉式单例
1、饿汉式单例:从系统运行开始,便长期占用内存,在调用速度与响应时间上都优于懒汉式单例,而且无需考虑多线程访问带来的安全问题。

//饿汉式单例
public class Singleton {
    private Singleton() {}
    private static Singleton instance = new Singleton();
    public static Singleton getInstance() {
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、懒汉式单例:实现了延迟加载,即在需要用到该对象时,才去实例化单例类,但是加载时间和响应速度上都不及饿汉式。而且需要考虑多线程安全问题,比较繁琐。

//懒汉式单例
public class Singleton2 {
    private Singleton2(){}
    public static synchronized void Init()//加同步锁
    {
        if(instance==null)
            instance=new Singleton2();
    }
    private static Singleton2 instance=null;
    public static Singleton2 getInstance()
    {
        if(instance==null)
          Init();
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3、一种更好的单例实现方法(IoDH)

//IoDH
class Singleton{
    private Singleton(){}

    public static class HolderClass{ //静态内部类
        private final static Singleton instance = new Singleton();  //其线程安全性由JVM来保证
    }
    public static Singleton getInstance()
    {
        return HolderClass.instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

通关使用IoDH,既可以实现延迟加载,又可以保证线程安全,而且不影响系统性能。但是其缺点和编程语言的特性有关。
四、总结
1、单例模式优点:
1)提供对唯一实例的受控访问
2)节约系统资源
3)允许可变数目的实例
2、单例模式缺点
1)扩展相对困难,没有抽象层
2)职责过重,一定程度上违背单一职责原则
3、使用场景:
1)、系统只需要一个实例对象。如:系统要求提供唯一的序列号生成器
2)、客户调用类的单个实例只允许使用一个公共访问点

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/729635
推荐阅读
相关标签
  

闽ICP备14008679号