设计模式 - 单例模式

简介

  • 饿汉模式:加载类的同时实例化。
  • 懒汉模式:用的时候才实例化。

场景

系统中,某些类只能有一个实例(例如文件系统管理器、系统计时工具),且需要在系统的任何地方都可以访问到。

这时,可以让类自身以静态属性的方式保存其唯一实例,并私有化构造方法,通过指定的方法获取这个实例。

模式定义

单例模式:确保某个类只有一个实例,而且由这个类负责自身的实例化并保存这个实例。

模式特点

符合单例模式的类有如下特点:

  • 只能有一个实例,保存在自身的静态私有成员变量中,通过公有的静态工厂方法获取
  • 构造方法私有
  • 全局都可以访问这个实例
  • 一般延迟初始化,在第一次使用时实例化

这里写图片描述

优点

  • 可以控制客户怎样以及何时访问某个类的实例
  • 可以节约系统资源
  • 可以基于单例模式进行扩展,获得指定个数的对象实例

缺点

  • 单例类扩展困难
  • 单例类的职责过重,违背单一职责原则

PHP 代码示例

假设需要对系统中某几种类的实例进行计数,计数类 Counter 采用的就是单例模式:

<?php

class Counter {
    private static $instance;
    private static $counter = 0;
    
    private function __construct() {
        
    }
    
    public static function getInstance() {
        if (empty(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function getCounter() {
        return self::$counter;
    }
    
    public function addCounter() {
        self::$counter++;
    }
}

class A {
    public function __construct() {
        $c = Counter::getInstance();
        $c->addCounter();
    }
}

class B {
    public function __construct() {
        $c = Counter::getInstance();
        $c->addCounter();
    }
}

$c = Counter::getInstance();
echo $c->getCounter();
new A();
echo $c->getCounter();
new A();
echo $c->getCounter();
new B();
echo $c->getCounter();

结果是:0123

Golang 示例

package main

import (
    "fmt"
    "sync"
)

// 饿汉模式,影响加载速度,线程安全
type singleton1 struct {}
var ins1 *singleton1 = &singleton1{}
func GetInstance1() *singleton1 {
	return ins1
}

// 懒汉模式,使用时才实例化,非线程安全
type singleton2 struct {}
var ins2 *singleton2
func GetInstance2() *singleton2 {
    if ins2 == nil {
        ins2 = &singleton2{}
    }
    return ins2
}

// 懒汉模式,加锁实现线程安全,低效版
type singleton3 struct {}
var ins3 *singleton3
var mu3 sync.Mutex
func GetInstance3() *singleton3 {
	mu3.Lock()
	defer mu3.Unlock()
	if ins3 == nil {
		ins3 = &singleton3{}
	}
	return ins3
}

// 懒汉模式,加锁实现线程安全,两次判断版
type singleton4 struct {}
var ins4 *singleton4
var mu4 sync.Mutex
func GetInstance4() *singleton4 {
	if ins4 == nil {
		mu4.Lock()
		defer mu4.Unlock()
		if ins4 == nil {
			ins4 = &singleton4{}
		}
	}
	return ins4
}

// sync.Once 实现,线程安全,高效
type singleton5 struct {}
var ins5 *singleton5
var once sync.Once
func GetInstance5() *singleton5 {
	once.Do(func() {
		ins5 = &singleton5{}
	})
	return ins5
}

func main() {
	i1 := GetInstance1()
	i2 := GetInstance2()
	i3 := GetInstance3()
	i4 := GetInstance4()
	i5 := GetInstance5()
	fmt.Println(i1, i2, i3, i4, i5)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值