Go 和 Java 对比学习:单例模式

JAVA 是较典型的面向对象语言 。如果说 C++ 是设计模式的发源地(GoF 的书使用 C++ 描述的),那么 Java 将设计模式发扬光大 。设计模式,很多人可能工作中没有用到,因为大部分人停留在写面条式的业务代码,从头撸到尾,没有设计可言 。但实际上,只要你用心思考,这样的场景下也是很有可能用上设计模式的 。特别是,当系统复杂时,设计模式的作用会很明显 。
虽然 Go 语言并非完全的面向对象语言,只提供了部分面向对象的特性,但一些设计模式还是可以使用的 。这个系列尝试讲解在 Go 中使用设计模式,同时给出 Java 对应的版本,进行对比学习 。另外,我们的设计模式不会局限在 GoF 的 23 中设计模式之中 。
在开始设计模式之前,有必要提一下面向对象的 SOLID 5 大设计原则:
名称缩写含义The Single Responsibility Principle(单一职责)S对象应该具有单一的职责 。这也是 Unix 的设计哲学The Open/Closed Principle(开/闭原则)O对扩展开发,对修改关闭The Liskov Substitution Principle(里氏替换)L对象应该可以在不破坏系统的情况下被子对象替换The Interface Segregation Principle(接口隔离)I不应强迫任何客户端依赖其不使用的方法The Dependency Inversion Principle(依赖倒转)D高级模块不应依赖于低级实现
遵循这样的设计原则,你的系统会更好维护 。
除了 SOLID 5 大设计原则,一些书上可能还会提到下面的设计原则:

  • 合成/聚合复用原则(Composite/Aggregate Reuse Principle):尽量使用合成/聚合,而不要使用继承 。这也是 Go 语言设计遵循的,基于此,Go 中没有继承 。
  • 迪米特法则(LoD),又叫 最少知识原则:一个对象应当对其他对象有尽可能少的了解;一个软件实体应当与尽可能少的其他实体发生相互作用 。
在你日常的工作中,可以运用以上原则审视你的设计,改进你的设计 。
今天先看第一个设计模式 。
1、单例模式简介面向对象中的单例模式是一个常见、简单的模式 。
英文名称:Singleton Pattern,该模式规定一个类只允许有一个实例,而且自行实例化并向整个系统提供这个实例 。因此单例模式的要点有:1)只有一个实例;2)必须自行创建;3)必须自行向整个系统提供这个实例 。
单例模式主要避免一个全局使用的类频繁地创建与销毁 。当你想控制实例的数量,或有时候不允许存在多实例时,单例模式就派上用场了 。
先看 Java 中的单例模式 。
Go 和 Java 对比学习:单例模式

文章插图
 
通过该类图我们可以看出,实现一个单例模式有如下要求:
  • 私有、静态的类实例变量;
  • 构造函数私有化;
  • 静态工厂方法,返回此类的唯一实例;
根据实例化的时机,单例模式一般分成饿汉式和懒汉式 。
  • 饿汉式:在定义 instance 时直接实例化,private static Singleton instance = new Singleton();
  • 懒汉式:在 getInstance 方法中进行实例化;
那两者有什么区别或优缺点?饿汉式单例类在自己被加载时就将自己实例化 。即便加载器是静态的,饿汉式单例类被加载时仍会将自己实例化 。单从资源利用率角度讲,这个比懒汉式单例类稍差些 。从速度和反应时间角度讲,则比懒汉式单例类稍好些 。然而,懒汉式单例类在实例化时,必须处理好在多个线程同时首次引用此类时的访问限制问题,特别是当单例类作为资源控制器在实例化时必须涉及资源初始化,而资源初始化很有可能耗费时间 。这意味着出现多线程同时首次引用此类的几率变得较大 。
2、单例模式的 Java 实现结合上面的讲解,以一个计数器为例,我们看看 Java 中饿汉式的实现:
public class Singleton {  private static final Singleton instance = new Singleton();  private int count = 0;  private Singleton() {}  public static Singleton getInstance() {    return instance;  }  public int Add() int {    this.count++;    return this.count;  }}代码很简单,不过多解释 。直接看懒汉式的实现:
public class Singleton {  private static Singleton instance = null;  private int count = 0;  private Singleton() {}  public static synchronized Singleton getInstance() {    if (instance == null) {      instance = new Singleton();    }    return instance;  }  public int Add() int {    this.count++;    return this.count;  }}


推荐阅读