单例模式探索

单例模式OC/C++探索

以前写OC中的单例很固定,一直都这样写,后来我就把它放在快捷代码块里面,只要输入singleton就直接输出这段代码

+ (instancetype)instance
{
    static Class *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

一直这样写,并没有关注内部实现
这两天一直在复习C++,然后看到了C++的单例模式,发现内部实现还是挺有讲究的

先来看OC中的
这个方法刚学OC的时候就记下来了
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);

官方文档的解释是,这个方法让block里面的代码在整个应用的生命周期里只执行一次,如果多线程同时调用,这个函数会让线程在block执行完之前都会同步地等待。只执行一次,顺带帮我们解决多线程问题,这是苹果帮我们封装好的,官方也建议用来写单例的方法!!

然后来看C++的

Class Singleton {
private:
 //构造函数
 Singleton();

 //静态对象
 static Singleton* instance;

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

首先,我们要把构造方法设置private,让别人无法调用构造方法
C++的静态对象和方法就像OC中的类的类对象和方法,类似在OC中是以+开头的方法
把instance和getInstance方法都设为静态,让类直接调用

这是一种实现方法,但是并没有考虑到线程安全
在getInstance()方法应该上锁

static Singleton* getInstance {
 lock(); //这里不实现上锁方法,只是探讨单例模式
 if(instance == NULL)
  instance = new Singleton();
 unlock(); //伪
}

假设有多个线程同时想要获取instance,当第一个线程上锁后其他线程只能等待,当一个线程解锁后(已经创建了instance)第二个线程才可以运行,接着第二个线程又加上锁,再创建instance,这时候已经重复创建了instance

进一步完善,当instance还没有创建的时候才需要加锁,等第二个线程上锁的时候再判断一次是否已经创建了instance

static Singleton* getInstance {
 if(instance == NULL){
  lock(); //伪
  if(instance == NULL)
   instance = new Singleton();
  unlock(); //伪
 }
}

另外,要保证只能从单例方法获取单例,不能赋值和拷贝
所以要声明赋值和拷贝方法,但是不实现

Singleton(const Singleton&){};
Singleton&operator=(const Singleton&){};

在C++11也可以这样

Singleton(const Singleton&) = delete;
Singleton&operator=(const Singleton&) = delete;

所以这是一种比较好的实现方法

Class Singleton {
private:
 //构造函数
 Singleton();

 //静态对象
 static Singleton* instance;

 //赋值和拷贝方法
 Singleton(const Singleton&){};
 Singleton&operator=(const Singleton&){};

public:
 static Singleton* getInstance {
  if(instance == NULL){
   lock(); //伪
   if(instance == NULL)
    instance = new Singleton();
   unlock(); //伪
  }
 }
}
关于类的静态成员

在C++中,静态成员不属于类的任何一个对象,所以它们并不是在创建类的对象时被定义的,它们不是由类的构造函数初始化的,一般来说不能再累的内部初始化静态成员,必须在类的外部定义和初始化每个静态成员,类似于全局变量,静态成员定义在任何函数之外,一旦被定义,将一直存在于成员的整个生命周期中
我们可以利用整个特性来写单例模式

class Singleton {
private:
 Singleton();
 static Singleton* instance;
public:
 static Singleton* getInstance{

  return instance;
 }
}
//然后在类外初始化
Singleton* Singleton::instance = new Singleton();

这种方法更加简洁,并且也是线程安全的,因为除了函数里面的静态变量,其他的静态变量都是在main函数之前就创建好了,单线程创建的,参考stackoverflow上的一个回答

在C#中可以直接在类内初始化

public sealed class Singleton {
 private Singleton(){}
 private static Singleton instance = new Singleton();
 public static Singleton getInstance {
  get
  {
   return instance;
  }
 }
}

这种方法比上一种二重锁的方法性能要更好
在C#中还有更好的方法

public sealed class Singleton {
 Singleton(){}
 public static Singleton getInstance{
  get {
   return Nested.instance;
  }
 }
 Class Nested{
  static Nested(){}
  internal static readonly Singleton instance = new Singleton();
 }
}

嵌套类,当用到Nested类的时候才会调用构造方法创建instance
由于无法实现类内初始化instance,所以这种方法我还不知道C++怎么实现
以上方法都是参考自剑指Offer

?

时间: 2024-08-07 09:05:40

单例模式探索的相关文章

Swift学习: 从Objective-C到Swift

文章组织脉络: 从Objective-C到Swift的语法差异.我们熟悉的Objective-C特性在Swift中如何展现. 从Objective-C到Swift的进步改进.研究对比Swift在安全性,易用性上的提升,给我们带来的新编程范式. 目录: 1.属性(property)和实例变量(instance variable) 2.控制流 3.函数 4.类与初始化(Initializers) 5.枚举与结构体 6.协议(Protocols) 7.Swift与Cocoa 8.总结 1.属性(pro

探索设计模式之----单例模式

Singleton模式可以是很简单的,它的全部只需要一个类就可以完成.但是如果在"对象创建的次数以及何时被创建"这两点上较真起来,Singleton模式可以相当的复杂. 结构是简单的,只是我们还有一些小小的要求如下: 1.最基本要求:每次从getInstance()都能返回一个且唯一的一个对象. 2.稍微高一点的要求:希望这个方法能适应多线程并发访问. 3.再提高一点的要求:方法性能尽可能高. 4.最后一点要求是:希望实现懒加载(Lazy Load),在需要的时候才被构造. 目的:希望

单例模式的一些探索

单例模式(Singleton)是软件开发中最常用的设计模式之一 单:唯一 例:实例 即某个类在整个系统中只能有一个实例对象可以被获取和使用 要点: 1).这个类在整个系统中只能有一个实例 --构造器私有化 2).这个类必须自己创建本身实例 --这个类中含有一个该类的静态变量来保存这个唯一的实例 3).这个类必须自己向整个系统暴露自身实例 --1.直接暴露 --2.使用静态变量的get方式获取 两种形式 一.直接创建对象(不存在线程安全问题) 1)直接实例化对象(简洁直观) 2)枚举式(最简洁)

Android开发艺术探索——第二章:IPC机制(上)

Android开发艺术探索--第二章:IPC机制(上) 本章主要讲解Android的IPC机制,首先介绍Android中的多进程概念以及多进程开发模式中常见的注意事项,接着介绍Android中的序列化机制和Binder,然后详细的介绍Bundle,文件共享,AIDL,Messenger,ContentProvider和Socker等进程间通讯的方法,为了更好的使用AIDL进行进程间通讯,本章引入了Binder连接池的概念,最后,本章讲解各种进程间通信方式的优缺点和使用场景,通过本章,可以让读者对

探索设计模式目录

探索设计模式之一——简单工厂模式 http://icyfenix.iteye.com/blog/575040 探索设计模式之二——工厂方法模式 http://icyfenix.iteye.com/blog/575045 探索设计模式之三——抽象工厂模式 探索设计模式之四——建造者模式 探索设计模式之五——原型模式 探索设计模式之六——单例模式

深入探索spring技术内幕(一): spring概述

一.Spring是什么? Spring是一个开源的控制反转 ( IoC ) 和面向切面 ( AOP ) 的容器框架, 它的主要目的是简化企业开发. 二.控制反转(IoC) 控制反转: 所谓的控制反转就是应用本身不负责依赖对象的创建及维护, 依赖对象的创建及维护是由外部容器负责的. 这样控制权就由应用转移到了外部容器, 控制权的转移就是所谓的反转. public class PersonServiceBean { // 自己new一个对象 private PersonDao personDao =

C++的黑科技(深入探索C++对象模型)

周二面了腾讯,之前只投了TST内推,貌似就是TST面试了 其中有一个问题,“如何产生一个不能被继承的类”,这道题我反反复复只想到,将父类的构造函数私有,让子类不能调用,最后归结出一个单例模式,但面试官说,单例模式作为此题的解答不够灵活,后来面试官提示说,可以用友元+虚继承,可以完美实现这样一个类 当然那时我还不太明白,友元与虚继承我都极少接触过,只是知道有这些东西,回头搜了一下“不能被继承的类”的做法,具体如下: 1,声明一个类,CNoHeritance,构造函数为private,并声明友元类C

Android开发艺术探索

Android开发艺术探索1 Activity的生命周期和启动模式 典型情况下生命周期异常情况下生命周期 启动模式标准模式栈顶复用模式栈内复用模式单实例模式 Activity的FlagsIntentFilter的匹配规则 2 IPC机制 进程间通信 SerializanleParcelableBinder 3 View的事件体系 事件分发机制 事件分发机制点击事件就是MotionEvent 事件分发其实就是对MotionEvent事件的分发三大方法dispatchTouchEvent 分发onI

【设计模式C++】单例模式

静态变量的内存分配和初始化 全局变量.non-local static变量(文件域的静态变量和类的静态成员变量)在main执行之前的静态初始化过程中分配内存并初始化:local static 变量(局部静态变量)则是在第一次使用时分配内存并初始化.这里的变量包含内置数据类型和自定义类型的对象. 静态变量初始化的线程安全性说明 非局部静态变量一般在main执行之前的静态初始化过程中分配内存并初始化,可以认为是线程安全的: 局部静态变量在编译时,编译器的实现一般是在初始化语句之前设置一个局部静态变量