设计模式之单例模式

设计模式之单例模式(Singleton Pattern

一、概述

单例模式是最简单的设计模式之一。此设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式包含一个单一的类,该类负责创建自己的对象,同时确保该类仅有一个实例。并且提供了一个访问其对象的全局访问点,可以直接访问,不需要实例化该类的对象。

总结:

  1. 单例模式中的类只能有一个实例。
  2. 该实例只能由自己创建,不可通过外部创建。
  3. 该类必须给外部对象一个访问点

二、应用实例

1、一个党只能有一个主席。

2Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。

3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

4、一个系统只能有一个窗口管理器或文件系统

5.、一个系统只能有一个计时工具或ID(序号)生成器

三、实现方式

1.构造函数私有化

       ①类外不可创建对象

       ②构造函数私有化的函数不能被继承

2.提供静态方法创建成员

        构造函数私有化-->类外不可创建对象-->初始时类外不能调用类内非静态公有函数-->在类内创建静态函数用来创建对象

四、类图

类图说明:
instance私有静态指针变量,用于存储唯一对象的指针
Singleton()私有构造方法,用于生成对象
getInstance()公用方法,提供给用户一个接口来获得对象指针

五、实现分析

以上我们了解了单例模式的特点以及实现单例模式的思路。

然而单例模式中由于对象的初始化的时间不同产生了两种情况(懒汉与饿汉):

      ①懒汉:顾名思义,它很懒,如果客户不需要实例,它就不会初始化对象,只有在客户需要时调用getInstance方法生成对象。

       特点:用时间换空间,对象延时生成,只在需要时才会生成的方法节省了空间

       ②饿汉:人在饿的时候都会饥不择食,所有此种情况在类加载时就生成对象

       特点:用空间换时间,在类初始化时就生成对象,占用了内存,但在调用时不需要重新生成,节省了时间。

虽然以上我们分析的比较详细了,但是在计算机中,计算机运行结果不一定如我们所料,因为计算机内部充满着并发。所以在对单例模式进行初始化操作时,如果两个线程同时调用了getInstance方法,岂不是会形成两个对象,这就与我们的初衷相违背。所以之后我们介绍线程不安全和线程安全的两种实现形式。

六、代码及说明

1.C++

①懒汉、线程不安全

Code

#include<iostream>
using namespace std;

class Singleton
{
	private:
		static Singleton *instance;
		Singleton()
		{
			///; 
		}
	public:
		static Singleton *getInstance()
		{
			if(!instance)
				instance=new Singleton();
			return instance;
		} 
};
Singleton *Singleton::instance=NULL;

int main()
{
	Singleton *p=Singleton::getInstance();
	Singleton *q=Singleton::getInstance();
	cout<<p<<endl;
	cout<<q<<endl;
}

Result:

        0x27a1440

        0x27a1440

②懒汉,线程安全(加锁)

Code

class Singleton
{
	private:
		static Singleton *instance;
		Singleton()
		{
			pthread_mutex_init(&mutex,NULL);
		}
	public:
		static pthread_mutex_t mutex;
		static Singleton *getInstance()
		{
			pthread_mutex_lock(&mutex);
			if(!instance)
				instance=new Singleto();
			pthread_mutex_unlock(&mutex);	
			return instance;
		} 
};
pthread_mutex_t Singleton::mutex;
Singleton *Singleton::instance=NULL;
③懒汉,线程安全(内部静态变量)(推荐)

    根据内部静态变量唯一性,保证只有一个实例生成,并且构造函数只会在第一次调用getInstance方法是调用,保证线程安全性,此方法为最佳版

Code

class Singleton{
	private:	
		Singleton()
		{
			///; 
		}
	public:
		static Singleton *getInstance()
		{
			static Singleton instance;
			return &instance;
		} 
};
④饿汉,线程安全(推荐)
Code
class Singleton
{
	private:
		static Singleton *instance;
		Singleton()
		{
			///; 
		}
	public:
		static Singleton *getInstance()
		{
			return instance;
		} 
};
Singleton *Singleton::instance=new Singleton();

2.JAVA

①懒汉,线程不安全

Code

public class Singleton
{
	private static Singleton instance;
	private Singleton()
	{
		///;
	}
	public static Singleton getInstance()
	{
		if(instance==null)
		{
			instance=new Singleton();
		}
		return instance;
	}
	
	
	public static void main(String args[])
	{
		Singleton p=Singleton.getInstance();
		Singleton q=Singleton.getInstance();
		
		System.out.println(p);
		System.out.println(q);
	}
}

Result:

        Singleton@6d06d69c

        Singleton@6d06d69c

②懒汉,线程安全(加锁1)

但每次调用方法都会产生同步,所以性能不好

public class Singleton
{
	private static Singleton instance;
	private Singleton()
	{
		///;
	}
	public static synchronized Singleton getInstance()
	{
		if(instance==null)
		{
			instance=new Singleton();
		}
		return instance;
	}
}
③懒汉,线程安全(加锁2,②的改进版

只有第一次调用方法时,才进行同步,但是可能多线程同时第一次调用,都通过第一次判空,所以在同步时,应该再次进行判空。

public class Singleton
{
	private static Singleton instance;
	private Singleton()
	{
		///;
	}
	public static Singleton getInstance()
	{
		if(instance==null)
		{
			synchronized(Singleton.class)
			{
				if(instance==null)
					instance=new Singleton();
			}
		}
		return instance;
	}
}
懒汉,线程安全(静态内部类)(推荐)

该方法利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗

public class Singleton
{
	private Singleton()
	{
		///;
	}
	private static class LazyHolder
	{
		private static final Singleton instance=new Singleton();
	}
	public static Singleton getInstance()
	{
		return LazyHolder.instance;
	}
}
饿汉,线程安全(推荐)
public class Singleton
{
	private static Singleton instance=new Singleton();
	private Singleton()
	{
		///;
	}
	public static Singleton getInstance()
	{
		return instance;
	}
}

六、优缺点

1.优点

①实例控制

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

②灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程

2.缺点

①开销

饿汉方式每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。

②可能的开发混淆

使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

③对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中,只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。

 

本章为所有设计模式的第一章,在进行编写的时候查阅了很多资料并且学到了很多,希望和大家一起分享。

如果在编写的时候出现了错误(尤其是代码部分)还希望大家积极指正。也希望有独特见解的朋友能够不吝赐教,与君共勉。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值