《大话设计模式》笔记:单例模式

有一些方法和属性是公共的,需要被全局使用,并且在整个应用程序的生存周期内存在,这时只需要维持有且仅有一个的类对象,重复地实例化是浪费内存且没有意义的。

复制粘贴是最容易的编程,也是最没价值的编程。

一、单例模式:

——保证一个类只有一个实例,并提供一个访问它的全局访问点。

通常我们可以定义全局变量使得一个对象被访问,但不能防止实例化多个对象。一个最好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其它实例可以被创建,并且它可以提供一个访问该实例的方法。除此之外,将判断全局变量是否创建的责任交给单例类自身处理,减少了重复代码。

librecad中用到的单例类例子:

class RS_Settings {
public:
	~RS_Settings();
	static RS_Settings* instance();
	//******************有省略********************************

private:
    RS_Settings();
	RS_Settings(RS_Settings const&) = delete;
	RS_Settings& operator = (RS_Settings const&) = delete;
	//******************有省略********************************
	
protected:
    static RS_Settings* uniqueInstance;
    //******************有省略********************************
};

RS_Settings* RS_Settings::uniqueInstance = nullptr;
RS_Settings* RS_Settings::instance() {
	if (!uniqueInstance) {
		uniqueInstance = new RS_Settings();
	}
	return uniqueInstance;
}

实用类:
和单例类相似,实用类也会采取私有化构造函数来避免该类存在实例,但是实用类不保存状态,仅仅提供一些静态方法或属性来让用户使用。单例类是有状态的,实用类不能用于继承多态,单例虽然实例唯一,确实可以有子类来继承。实用类不过是一些方法属性的集合,而单例却是有着唯一的对象实例。

librecad中用到的实用类例子:

class RS_Math {
private:
	RS_Math() = delete;
public:
    static int round(double v);
    static double round(const double v, const double precision);
    static double pow(double x, double y);
    static RS_Vector pow(RS_Vector x, double y);
    static bool equal(const double d1, const double d2);
    //******************有省略********************************
};

二、多线程时的单例:

多个线程同时访问上述示例单例类时,调用instance()方法会有可能创建多个实例,这时可以通过给进程一把锁来处理,确保一个线程位于代码的临界区时,另一个线程不进入临界区,如果其它线程试图进入锁定的代码,则将一直等待,直到该对象被释放。

RS_Settings* RS_Settings::uniqueInstance = nullptr;
std::mutex RS_Settings::m_Mutex;//在h文件被声明为静态成员变量

RS_Settings* RS_Settings::instance() {
	std::unique_lock<std::mutex> lock(m_Mutex); 
	if (!uniqueInstance) {
		uniqueInstance = new RS_Settings();
	}
	return uniqueInstance;
}

这样每次调用instance方法都需要lock,会影响性能。改用双重锁定。

RS_Settings* RS_Settings::uniqueInstance = nullptr;
std::mutex RS_Settings::m_Mutex;//在h文件被声明为静态成员变量

RS_Settings* RS_Settings::instance() {
	if (!uniqueInstance) {
		std::unique_lock<std::mutex> lock(m_Mutex); 
		if (!uniqueInstance) {
			uniqueInstance = new RS_Settings();
		}
		return uniqueInstance;
	}
}

三、“饿汉式”单例类:

上述单例类为懒汉式,要在第一次引用时才将自己实例化。而使用静态初始化的方式在自己被加载的时候就将自己实例化,这样的方法称为“饿汉式”。

class RS_Settings {
public:
	~RS_Settings();
	static RS_Settings* instance();
	//******************有省略********************************

private:
    RS_Settings();
	RS_Settings(RS_Settings const&) = delete;
	RS_Settings& operator = (RS_Settings const&) = delete;
	//******************有省略********************************
	
protected:
    static RS_Settings* uniqueInstance;
    //******************有省略********************************
};

RS_Settings* RS_Settings::uniqueInstance = new RS_Settings;
RS_Settings* RS_Settings::instance() {
	return uniqueInstance;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值