文章目录
创建型模式(上)
- 创建型模式共五种,包括:单例模式、建造者模式、工厂方法模式、抽象工厂模式、原型模式,本文介绍前面2种。
- 单例模式
- 建造者模式
- 工厂方法模式
- 抽象工厂模式
- 原型模式
一、单例模式
1.1 定义
- 单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1.2 优点和使用场景
- 1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
- 2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
- 3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
1.3 实现
1.3.1 恶汉式
1.3.1.1 饿汉式(静态常量/静态代码块)[可用]
- 代码
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
//static {
// INSTANCE = new Singleton();
//}
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
- 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
- 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
1.3.2 懒汉式
1.3.2.1 懒汉式(线程安全,同步方法)[不推荐用]
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
- 效率低,不推荐使用
1.3.2.2 双重检查[推荐用]
- 代码
public class Singleton {
//增加volatile关键字,保证内存的可见性和禁止指令重排,后者可以保证线程初始化singleton的时候执行顺序不会被重排
//前者可以保证一个线程初始化了singleton之后,对另一个线程立刻可见
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
//这里不是原子操作,这里包含3步,这里的指令重排可能导致3步骤还未执行完,另一个线程就在外面判定 //singleton不是null,导致另一个线程获取到的singleton是不完整的
//1.分配一块内存空间
//2.在这块内存上初始化一个DoubleCheckLock的实例
//3.将声明的引用instance指向这块内存
singleton = new Singleton();
}
}
}
return singleton;
}
}
- 优点:线程安全;延迟加载;效率较高。
1.3.2.3 静态内部类[推荐用]
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
- 这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
- 优点:避免了线程不安全,延迟加载,效率高。
1.3.3 枚举[使用较少]
- 代码
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
- 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中,很少见人这么写过。
二、建造者模式
2.1 定义
- 使用多个简单的步骤一步一步构建一个复杂的对象,属于创建型设计模式。
2.2 优点和使用场景
- 用于创建复杂的对象,对象内部结构复杂,实例化时需要屏蔽内部细节,当对象参数过多时可以考虑使用。
- 完整的建者模式包括产品接口,具体的产品类,建造接口,具体的建造器类,导演类,这样的模式下外部不需要参与到建造的过程,但是感觉在源码中这样的用的不多,下面代码中使用简单的代码实现建造者模式,只有一个具体的产品类,建造器类和测试类
2.3 实现
- 产品类
//产品类
public class House {
private String type; //类型
private String bedroom; //卧室
private String diningRoom; //餐厅
private String livingRoom; //客厅
private String balcony; //阳台
private String washRoom; //洗漱间
//省略get/set/ToString方法
}
- 建造器类
//建造器类
public class HouseBuilder {
private House house;
public HouseBuilder() {
this.house = new House();
}
public HouseBuilder type(String type) {
house.setType(type);
return this;
}
public HouseBuilder bedroom(String bedroom) {
house.setBedroom(bedroom);
return this;
}
public HouseBuilder diningRoom(String diningRoom) {
house.setDiningRoom(diningRoom);
return this;
}
public HouseBuilder livingRoom(String livingRoom) {
house.setLivingRoom(livingRoom);
return this;
}
public HouseBuilder balcony(String balcony) {
house.setBalcony(balcony);
return this;
}
public HouseBuilder washRoom(String washRoom) {
house.setWashRoom(washRoom);
return this;
}
public House build() {
return house;
}
}
- 测试类
public class BuilderTest {
public static void main(String[] args) {
HouseBuilder builder = new HouseBuilder();
House bigHouse = builder.type("商品房").bedroom("3个卧室")
.livingRoom("大客厅").diningRoom("大餐厅")
.balcony("大阳台").washRoom("双卫").build();
System.out.println(bigHouse);
House smallHouse = builder.type("公寓").bedroom("2个卧室")
.livingRoom("小客厅").diningRoom("小餐厅")
.balcony("小阳台").washRoom("单卫").build();
System.out.println(smallHouse);
}
}
- 打印
打印:
House{type='商品房', bedroom='3个卧室', diningRoom='大餐厅', livingRoom='大客厅', balcony='大阳台', washRoom='双卫'}
House{type='公寓', bedroom='2个卧室', diningRoom='小餐厅', livingRoom='小客厅', balcony='小阳台', washRoom='单卫'}
三、小结
3.1 建造者模式和工厂模式的区别
-
建造者模式:简化构造过程但是将构造的过程对外开放,使用者参与对象的创建过程。
-
工厂模式:将对象的创建和使用分开,屏蔽创建细节,对外提供可用的对象,使用者并不关心创建细节。
-
对象的复杂程度:建造者更加复杂
-
客户端的参与程度:一高一低
-
将在"创建型模式(下)"的文章中介绍后面三种设计模式