每天一个设计模式(五)——单例模式

什么用

实际上我们经常见到这种设计模式。当你要打印东西时,你有很多个打印任务,但正在工作的却只有一个;当你从数据库获取数据时,看上去你会建立很多次连接,但其实你的连接都是从唯一的数据库连接池中获取的;还有Spring中的bean一般默认是单例的。

对于这种要么没有实例,有就只有一个实例的类,我们可以让类自己保存它的唯一实例,保证没有其他实例被创建,并且向外部提供一个访问该实例的方法。

模式结构

  • 单例类
    负责保证只能创建一个实例,且外部可访问该实例。

优缺点

优点
  • 提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,确保所有的对象都访问一个实例。
  • 节约系统资源。对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
  • 允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
缺点
  • 由于单例模式没有抽象层,因此单例类的扩展有很大的困难。
  • 一定程度上违背了单一职责原则。因为单例类不仅需要负责实例的创建,还要对创建的实例是否唯一进行判断,既充当了工厂角色,又充当了产品角色,将产品的创建与产品本身的功能融合到了一起。

适用情况

  • 频繁实例化然后销毁的对象
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 频繁访问 IO 资源的对象,例如数据库连接池或访问本地文件。

扩展

  • 与实用类的区别。实用类没有状态,只是一些方法属性的集合;单例类有状态,且可以有子类来继承。
  • 使用懒单例模式时注意线程安全问题。
  • 不能用反射模式创建单例,否则会实例化一个新的对象。

实际应用

  • 数据库连接池
  • 线程池

代码示例

https://github.com/zero4eva/design_pattern

这里只给出最简单常用的饿汉方法,上面的github有其他的实现

  • PrinterTest.java
public class PrintTest {
    public static void main(String[] args) {
        String file = "xxx.doc";
        SimpleLazyPrinter printer1 = SimpleLazyPrinter.getInstance();
        printer1.print(file);

        SimpleLazyPrinter printer2 = SimpleLazyPrinter.getInstance();
        System.out.println(printer1 == printer2);
    }
}
  • SimpleHungryPrinter.java
    // 饿汉式,线程安全
    public class SimpleHungryPrinter {
    
        // 将构造器私有,禁止外界通过构造器创建实例
        private SimpleHungryPrinter() {
        }
    
        // 类加载的时候就创建该实例
        private static SimpleHungryPrinter instance = new SimpleHungryPrinter();
    
        // 只能通过该方法获取实例
        public static SimpleHungryPrinter getInstance() {
            return instance;
        }
    
        public void print(String file) {
            System.out.println("print " + file + " now...");
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值