首页 > 其他分享 >单件模式

单件模式

时间:2022-12-15 20:57:24浏览次数:37  
标签:Singleton 锅炉 单件 模式 uniqueInstance 实例 public

时间会让人成长,但是不会指明方向

剖析经典的单件模式

public class Singleton {
// 利用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
   
   // 私有化类构造器
   private Singleton() {}
   
   // 获取类单件实例
   public static Singleton getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new Singleton();
      }
       return uniqueInstance;
  }
}

别人想要获取这个类的实例,就必须“请求”得到一个实例,而不是自行实例化得到。类中有一个静态方法,叫做getInstance()。调用这个方法,单件实例就现身了,这个单件可能是在这次调用的时候被创建出来的,也可能是以前早就被创建出来的。

巧克力工厂

现代化的巧克力工厂具备计算机控制的巧克力锅炉,锅炉做的事,就是把巧克力和牛奶融合在一起,然后在下一个阶段,制造成巧克力。

下面是一个巧克力锅炉制造器的代码,你会发现代码写得非常小心,他们在努力防止不好的事情发生,因为一个不小心就会造成事故。例如:排出500加仑的未煮沸的混合物,或者锅炉已经加满了还继续放原料,或者锅炉内好没放原料就开始空烧。

public class ChocolateBoiler {
private boolean empty;
   private boolean boiled;
   
   public ChocloateBoiler() {
       // 代码开始时,锅炉是空的,未煮沸的
       empty = true;
       boiled = false;
  }
   
   public void fill() {
       // 在锅炉内填充原料时,锅炉必须是空的
       if (isEmpty()) {
           empty = false;
           boiled = false;
           // 在锅炉中填满巧克力和牛奶的混合物
      }
  }
   
   public void drain() {
       // 锅炉排出时,必须是满的且是煮沸的
       if (!isEmpty() && isBoiled()) {
// 排出煮沸的巧克力和牛奶
           empty = true;
      }
  }
   
   public void boil() {
       // 煮混合物时,锅炉必须是满的,且没有煮过的
       if (!isEmpty() && !isBoiled()) {
           // 将锅炉内物煮沸
           boiled = true;
      }
  }
   
   public boolean isEmpty() {
       return empty;
  }
   
   public boolean isBoiled() {
       return boiled;
  }
}

如果只存在一个锅炉类的实例,制作流程可以有条不紊地进行下去。但是如果同时存在多个锅炉实例呢,那就可能会发生很糟糕的事情。

利用单件模式改进巧克力工厂

将构造函数私有化,且写一个获取单例的getInstance()方法。

public class ChocolateBoiler {
private boolean empty;
   private boolean boiled;
   
   public static ChocolateBoiler getInstance() {
  private ChocloateBoiler() {
       // 代码开始时,锅炉是空的,未煮沸的
       empty = true;
       boiled = false;
  }
  }
   
   public void fill() {
       // 在锅炉内填充原料时,锅炉必须是空的
       if (isEmpty()) {
           empty = false;
           boiled = false;
           // 在锅炉中填满巧克力和牛奶的混合物
      }
  }
   
   public void drain() {
       // 锅炉排出时,必须是满的且是煮沸的
       if (!isEmpty() && isBoiled()) {
// 排出煮沸的巧克力和牛奶
           empty = true;
      }
  }
   
   public void boil() {
       // 煮混合物时,锅炉必须是满的,且没有煮过的
       if (!isEmpty() && !isBoiled()) {
           // 将锅炉内物煮沸
           boiled = true;
      }
  }
   
   public boolean isEmpty() {
       return empty;
  }
   
   public boolean isBoiled() {
       return boiled;
  }
}

定义单件模式

确保一个类只有一个实例,并且提供一个全局访问点。

  • uniqueInstance类变量持有唯一的单件实例.

  • getInstance()方法是静态的,这意味着它是一个类方法,所以可以在代码的任何地方使用Singleton.getInstance()访问它。这和访问全局变量一样简单,只是多了一个优点,单件可以延迟实例化。

多线程的麻烦

尽管我们使用了经典的单件模式来修改代码,但是在实际的运行过程中还是出现了问题,在锅炉加热的过程中,机子还在不停地加入原料。

原因:多线程的调用。

ChocolateBoiler boiler = ChocolateBoiler.getInstance();

// 多线程出现
fill();
boil();
drain();

这样就导致了上面糟糕情况的发生。

解决多线程带来的问题

  1. 同步getInstance()方法

通过加锁的方式,保证不会有两个线程可以同时进入这个方法。

public class Singleton {
// 利用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
   
   // 私有化类构造器
   private Singleton() {}
   
   // 获取类单件实例
   public static synchronized Singleton getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new Singleton();
      }
       return uniqueInstance;
  }
}

弊端:加锁同步会影响性能。

如果你的程序对这点性能不是很影响的话,可以考虑使用。

  1. 急切实例化(类初始化就创建)

public class Singleton {
private static Singleton uniqueInstance = new Singleton();
   
   // 私有化类构造器
   private Singleton() {}
   
   // 获取类单件实例
   public static Singleton getInstance() {
       return uniqueInstance;
  }
}

利用这个做法,我们依赖JVM在这个类加载时就创建唯一的单件实例。

弊端:如果这个类比较占用系统资源,就会造成资源的浪费。

  1. 双重检查锁

首先先检查实例是否创建,如果没有创建才进行同步,已经创建了,就不进行同步操作。

public class Singleton {
private volatile static Singleton uniqueInstance = new Singleton();
   
   // 私有化类构造器
   private Singleton() {}
   
   // 获取类单件实例
   public static Singleton getInstance() {
  if (uniqueInstance == null) {
  synchronized (Singleton.class) {
  if (uniqueInstance == null) {
  uniqueInstance = new Singleton();
  }
  }
  }
       return uniqueInstance;
  }
}
 

标签:Singleton,锅炉,单件,模式,uniqueInstance,实例,public
From: https://www.cnblogs.com/l12138h/p/16986000.html

相关文章

  • 做了MVC模式一年,可不要把传统模式忘记呀!ashx配合aspx实现AJAX加载JSON数据
    ASHX内容:#regionIHttpHandlerMemberspublicvoidProcessRequest(HttpContextcontext){context.Response.ContentType="application/x......
  • 说说设计模式~ 观察者模式与消费者模式的区别
    ​​返回目录​​再说概念这两个模式确实有点相似,都为了实现程序的解耦产生的,观察者一般又称发布/订阅模式,它一般是有一个主题对象,然后有多个订阅者去关注它,当它的状态发生......
  • 模式识别,模式识别70年学科发展报告基础篇
    模式识别学科发展报告头版模式识别国家重点实验室编写中国科学院学科发展战略研究项目成果 该报告摘录了最近50项重要研究进展未来30个重要研究问题 分模式识别......
  • VMware虚拟机NAT模式端口转发
    作用虚拟机网络选择NAT方式,启用端口转发,可以实现宿主机器和虚拟机的端口映射 如果我们把映射虚拟机的端口设为22,就可以通过宿主机器ip加端口直接远程虚拟机了 操......
  • 【分享一个工具】通过定义proto3来自动生成多进程模式的插件代码
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯我在多进程插件框架hashicorp/go-plugin的基础上,使用pro......
  • 桥接网络配置模式文档1
    桥接网络配置模式文档使用虚拟机vmware 版本15创建好虚拟机以后配置选择桥接模式实现网段最后的互通 2 点击设置后选择桥接模式   3 点击编辑选择虚拟网络......
  • 建造者模式
     ​​http://blog.51cto.com/craftsman001/1662488​​建造者模式需要四大角色:(1)目标者类Target:有n个属性。不能多变。(2)抽象建造者接口Builder:关联目标类Target,对应n个属性......
  • 单例模式
    首先介绍一下单例模式:    单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要......
  • 简单工厂模式(创建型)
    如何创建一个对象?publicinterfaceProductpublicclassAppleProductpublicclassGoogleProductpublicclassBananaProduct###########################################......
  • 工厂模式
    想多了都是问题,想通了都是答案第一部分,简单工厂模式哪朵玫瑰没有荆棘,最好的报复是美丽,最美的盛开是反击,别让谁去改变了你。当看到new,就会想到具体先看一段代码Duck......