六大常用设计模式:一、单例模式

1.1、介绍

单例模式(Singleton)的目的是为了保证在一个进程中,某个类有且仅有一个实例。它解决了一个全局使用的类频繁地创建和销毁这一问题。

这个全局使用的类 在单例模式中需要创建自己的对象,同时确保只有单个对象被创建。并且这个类需要提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象

单例模式特点有三:单例类只能有一个示例;单例类必须自己常见自己的唯一实例;单例类必须给所有其他对象提供这一实例。

这种类型的设计模式属于创建型模式。

下面介绍两种单例模式的实现:饿汉式、懒汉式。

1.2、饿汉式单例模式

该模式特点是:类一旦加载就创建一个单例,保证在调用 getInstance() 方法之前单例已经存在了。

public class Hungry {
    private byte[] data1 = new byte[1024*1024];
    private byte[] data2 = new byte[1024*1024];
    private byte[] data3 = new byte[1024*1024];

    // 只要是单例模式,一定要构造器私有
    private Hungry(){
    }

    private final static Hungry HUNGRY = new Hungry();

    // 对外的方法
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

饿汉式单例 在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。

1.3、懒汉式单例模式

该模式特点是:类加载时没有生成单例,只有当第一次调用 getInstance() 方法时才去创建这个单例。

public class LazyMan {
    // 只要是单例模式,一定要构造器私有
    private LazyMan() {
        System.out.println(Thread.currentThread().getName() + "ok");
    }

    // 用的时候再加载对象,先放在这里
    private volatile static LazyMan lazyMan;

    // 对外的方法
    public static LazyMan getInstance() {
        if (lazyMan==null){
            synchronized (LazyMan.class){
                if (lazyMan == null) {
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
}

懒汉式单例模式下,如果加载多线程程序,一定要使用关键字 volatilesynchronized 形成双重检测锁模式(DCL懒汉式),避免线程不安全问题。另外懒汉式单例也存在缺点:就是每次访问时都要同步,会影响性能,且消耗更多的资源。

1.4、优缺点

单例模式可以保证内存中只有一个实例,减少了内存的开销,可以避免资源的多重占用,并且由于单例模式设置了全局访问点,可以优化和共享资源的访问

但同样存在缺点。

单例模式一般没有接口,难以扩展。(要想扩展,只能修改原来的代码,但这样违背了开闭原则)

在并发测试中,单例模式不利于代码调试。(因为在调试过程中,如果单例中的代码没有执行完,不能模拟生成一个新的对象)

单例模式的功能代码通常写在一个类中,如果功能设计不合理,那么很容易违背单一职责原则。

1.5、使用 Java 中的 enum 实现单例模式

另一种实现 Singleton 的方式是利用Java的 enum ,因为Java保证枚举类的每个枚举都是单例,所以我们只需要编写一个只有一个枚举的类即可:

public enum World {
    // 唯一枚举:
	INSTANCE;

	private String name = "world";

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

枚举类也完全可以像其他类那样定义自己的字段、方法,这样上面这个 World 类在调用方看来就可以这么用:

String name = World.INSTANCE.getName();

使用枚举实现Singleton还避免了饿汉式单例的一个潜在问题:即序列化和反序列化会绕过普通类的 private 构造方法从而创建出多个实例,而枚举类就没有这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值