• 【go写设计模式】单例模式全都用我的


    单例模式

    问题

    为什么要有单例模式?

    第一是不想浪费资源,多次初始化会造成浪费。都用我的就好了。
    其次是统一,如果是需要统一的东西,那就只创立一个入口,让大家只能用我的。

    使用场景

    • 需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。
    • 某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
    • 某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
    • 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
    • 频繁访问数据库或文件的对象。
    • 对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。
    • 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。

    实现

    懒汉式:在使用的时候再初始化。针对要强制统一的情况。
    饿汉式:最开始就初始化。针对不想浪费资源的情况,是大量使用的类。

    代码

    //Singleton 懒汉式单例
    type Singleton struct{}
    
    var singleton *Singleton
    var once sync.Once
    
    //GetInstance 用于获取单例模式对象
    func GetInstance() *Singleton {
    	once.Do(func() {
    		singleton = &Singleton{}
    	})
    	return singleton
    }
    
    // Singleton2 饿汉式单例
    type Singleton2 struct{}
    
    var singleton2 *Singleton2
    
    func init() {
    	singleton2 = &Singleton2{}
    }
    
    // GetInstance 获取实例
    func GetInstance2() *Singleton2 {
    	return singleton2
    }
    

    单元测试

    package singleton
    
    import (
    	"sync"
    	"testing"
    )
    
    const parCount = 100
    
    func TestSingleton(t *testing.T) {
    	ins1 := GetInstance()
    	ins2 := GetInstance()
    	if ins1 != ins2 {
    		t.Fatal("instance is not equal")
    	}
    }
    
    func TestParallelSingleton(t *testing.T) {
    	wg := sync.WaitGroup{}
    	wg.Add(parCount)
    	instances := [parCount]*Singleton{}
    	for i := 0; i < parCount; i++ {
    		go func(index int) {
    			instances[index] = GetInstance()
    			wg.Done()
    		}(i)
    	}
    	wg.Wait()
    	for i := 1; i < parCount; i++ {
    		if instances[i] != instances[i-1] {
    			t.Fatal("instance is not equal")
    		}
    	}
    }
    
    func TestSingleton2(t *testing.T) {
    	ins1 := GetInstance2()
    	ins2 := GetInstance2()
    	if ins1 != ins2 {
    		t.Fatal("instance is not equal")
    	}
    }
    
    func TestParallelSingleton2(t *testing.T) {
    	wg := sync.WaitGroup{}
    	wg.Add(parCount)
    	instances := [parCount]*Singleton2{}
    	for i := 0; i < parCount; i++ {
    		go func(index int) {
    			instances[index] = GetInstance2()
    			wg.Done()
    		}(i)
    	}
    	wg.Wait()
    	for i := 1; i < parCount; i++ {
    		if instances[i] != instances[i-1] {
    			t.Fatal("instance is not equal")
    		}
    	}
    }
    
    

    单例模式的优点:

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

    单例模式的缺点:

    • 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
    • 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
    • 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

    其实凡是有利就有弊,只要针对自己的场景选择合适的模式就好了。

    单例模式.png

  • 相关阅读:
    CodeForces 687B Remainders Game
    CodeForces 689D Friends and Subsequences
    CSU 1810 Reverse
    生成树收录
    吃奶酪
    带逆向思维的并查集
    中位数定理
    种类并查集(关押犯人)
    带权并查集
    分层图
  • 原文地址:https://www.cnblogs.com/HappyTeemo/p/16283660.html
Copyright © 2020-2023  润新知