01-创建型模式(上)

本文介绍创建型模式中的单例模式和建造者模式。单例模式能保证一个JVM中对象只有一个实例,有多种实现方式;建造者模式用于创建复杂对象,可屏蔽内部细节。还对建造者模式和工厂模式的区别进行了小结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建型模式(上)

  • 创建型模式共五种,包括:单例模式、建造者模式、工厂方法模式、抽象工厂模式、原型模式,本文介绍前面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 建造者模式和工厂模式的区别

  • 建造者模式:简化构造过程但是将构造的过程对外开放,使用者参与对象的创建过程。

  • 工厂模式:将对象的创建和使用分开,屏蔽创建细节,对外提供可用的对象,使用者并不关心创建细节。

  • 对象的复杂程度:建造者更加复杂

  • 客户端的参与程度:一高一低

  • 将在"创建型模式(下)"的文章中介绍后面三种设计模式

3.2 参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值