单例模式 Singleton
单例模式(Singleton)让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
适用场景
- 如果程序中的某个类对于所有客户端只能有一个可用的实例。
- 如果需要更加严格地控制全局变量。
核心步骤
- 将默认构造函数设为私有, 防止其他对象使用单例类的
new
运算符。 - 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。
不同情况
单线程单例
public final class Singleton {
private static Singleton instance;
public String value;
// 隐藏构造函数
private Singleton(String value) {
this.value = value;
}
// 静态构造方法
public static Singleton getInstance(String value) {
if (instance == null) {
instance = new Singleton(value);
}
return instance;
}
}
// 实现
public class DemoSingleThread {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance("1");
Singleton anotherSingleton = Singleton.getInstance("2");
System.out.println(singleton.value); // 结果为1
System.out.println(anotherSingleton.value); // 结果还是1
}
}
多线程单例
public final class Singleton {
// 将instance用volatile关键字修饰,使得实例在多线程中可见
private static volatile Singleton instance;
public String value;
private Singleton(String value) {
this.value = value;
}
public static Singleton getInstance(String value) {
// 使用双重检查锁定(DCL)方法,必须配合上面的volatile关键词修饰的instance才是完美的
if (instance != null) { // 第一次检查,不通过就不需要执行下面的加锁和初始化操作,减少性能开销
return result;
}
synchronized(Singleton.class) { // 锁
if (instance == null) { // 第二次检查,能确定是否真正没有实例
instance = new Singleton(value); // 创建单例
}
return instance;
}
}
}
// 实现
public class DemoMultiThread {
public static void main(String[] args) {
Thread threadFoo = new Thread(new ThreadFoo());
Thread threadBar = new Thread(new ThreadBar());
threadFoo.start();
threadBar.start();
}
static class ThreadFoo implements Runnable {
@Override
public void run() {
Singleton singleton = Singleton.getInstance("FOO");
System.out.println(singleton.value);
}
}
static class ThreadBar implements Runnable {
@Override
public void run() {
Singleton singleton = Singleton.getInstance("BAR");
System.out.println(singleton.value);
}
}
} // 最终都输出1
原型模式 Prototype
原型模式(Prototype)让你能够复制已有对象, 而又无需使代码依赖它们所属的类。
适用场景
在代码开发中,希望不用知道对象的所有配置和依赖而快速生成与其完全相同的一个复制品。
场景模拟
假如我们有一个细胞cell
,需要进行有丝分裂Mitosis
,其中染色体内容是复杂且不可见的。
实现流程
-
创建原型接口,并在其中声明
克隆
方法。public interface Mitosis { // 接口声明放回类型的基类 public Object doingMitosis(); }
-
原型类必须另行定义一个以该类对象为参数的构造函数。构造函数必须复制参数对象中的所有成员变量值到新建实体中。每个类都必须显式重写克隆方法并使用自身类名调用
new
运算符。否则,克隆方法可能会生成父类的对象。public class Cell implements Mitosis { private String DNA; public Cell() { DNA = "AGCTGATCAAGTCTCGATC"; } // 一定要定义一个以该类对象为参数的构造函数,这是复制的入口 public Cell(Cell cell) { if (cell != null) { // 复制参数对象中的所有成员变量值到新建实体中 this.DNA = cell.DNA; } } public void geneEditing(String eDNA) { this.DNA = eDNA; } // 使用new运算符调用原型版本的构造函数 @Override public Cell doingMitosis() { // 调用自身类名 return new Cell(this); } @Override public boolean equals(Object object) { if (!(object instanceof Cell)) return false; Cell cell = (Cell) object; return cell.DNA == DNA; } }
-
测试
public class Demo { public static void main(String[] args) { Cell cell = new Cell(); cell.geneEditing("TAACGCTAGCTAGCTAGCT"); // 有丝分裂 Cell copyCell = cell.doingMitosis(); // 比较遗传物质 System.out.println(cell.equals(copyCell)); // true } }