单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象。
1. 单例模式的结构
单例模式主要有以下角色:
| 角色 | 职责 |
|---|---|
| 单例类 | 只能创建一个实例的类 |
| 访问类 | 使用单例类 |
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式主要有以下角色:
| 角色 | 职责 |
|---|---|
| 单例类 | 只能创建一个实例的类 |
| 访问类 | 使用单例类 |
创建型模式(Creational Pattern)关注对象的创建过程,核心思想是将对象的创建与使用解耦:使用方不必关心对象是如何 new 出来、如何初始化的,只需要向创建逻辑"要"一个对象即可。这样做的直接好处是,当创建逻辑发生变化(比如改为缓存复用、改为按配置生成不同子类)时,使用方的代码不需要改动。
GoF 设计模式中的创建型模式包括单例、原型、工厂方法、抽象工厂和建造者 5 种。它们解决的问题各不相同:
| 模式 | 核心问题 | 一句话概括 |
|---|---|---|
| 单例模式 | 如何保证一个类只有一个实例 | 全局唯一实例,如 Runtime |
| 工厂模式 | 创建哪种对象应由调用方之外的地方决定 | 把"new 对象"交给工厂,调用方面向接口 |
| 原型模式 | 如何高效地创建大量相似的复杂对象 | 克隆已有对象而不是重新 new |
| 建造者模式 | 如何分步骤构建一个复杂的组合对象 | 把构建过程与表示分离,链式组装 |
需求:设计一个咖啡店点餐系统。
设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡 AmericanCoffee 和拿铁咖啡 LatteCoffee);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。
具体类的设计如下:
在 Java 中,万物皆对象,这些对象都需要创建。如果创建的时候直接 new 该对象,就会对该对象耦合严重,假如我们要更换对象,所有 new 对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦:如果要更换对象,直接在工厂里更换该对象即可。所以说,工厂模式最大的优点就是:解耦。
定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
通俗地说:当创建新对象的成本很高(比如需要查询数据库、做大量初始化计算),或者新对象与某个已有对象绝大部分状态相同时,"复制一个现成的再改一改"往往比"从零 new 一个"更划算。
原型模式包含如下角色:
| 角色 | 职责 |
|---|---|
| 抽象原型类 | 规定了具体原型对象必须实现的 clone() 方法 |
| 具体原型类 | 实现抽象原型类的 clone() 方法,它是可被复制的对象 |
| 访问类 | 使用具体原型类中的 clone() 方法来复制新的对象 |
定义:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
学完各个创建型模式后,最容易出现的问题是"这几个模式看起来都能创建对象,到底该用哪个?"。本篇把最容易混淆的两组模式放在一起对比,帮助建立选择依据。
工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
我们举个简单例子来说明两者的差异:如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就诞生了。