首页 > 其他分享 >C语言单例模式

C语言单例模式

时间:2023-07-07 19:24:28浏览次数:38  
标签:const file fileManager 模式 C语言 char 单例 fileName main

单例模式的定义

​ 单例模式的需求是保证在代码的整个运行期间,某种数据类型只有一个唯一的实例子。并且提供一个全局的访问接口。

我们可以从两个角度来理解单例模式

  • 数据类型有且仅可以创建一个实例,编程人员不可以的随意的定义的此类型的实例。我们必须限制这种数据结构的创建。
  • 访问接口是全局唯一实例的访问接口。

单例模式的实现

​ 一般单例模式按照创建对象创建和调用的时序关系可分为懒汉式和饥汉式。饥汉式一般在程序启动时创建对象,非Lazy初始化;懒汉式在真正使用时在创建,采用Lazy初始化。

饿汉式

​ 饿汉式,就像饿汉一样,不论自身需要与否,在程序启动时即开始创建。在C++中一般声明为全局变量实现饿汉式,全局变量会在main函数执行之前创建全局变量对象,在main函数执行结束之后释放全局变量

	可执行程序有一个全局_CTOR_LIST函数指针数组,编译器在链接时会把全局变量的构造函数指针添加到_CTOR_LIST中;然后可执行程序在执行main函数之前,会遍历并执行此_CTOR_LIST中的所有函数指针,这样就完成了全局变量的构造。

	同样可执行程序也存在一个全局_DTOR_LIST函数指针数组,编译器在链接时会把全局变量的析构 函数指针添加到_DTOR_LIST;在可执行程序执行main函数之后,会遍历并执行此_DTOR_LIST中的所有函数指针,这样就完成了全局变量的析构。

​ 熟悉了C++饿汉式全局变量的构造过程,我们参考全局变量原理构造原理实现C语言饥汉式。幸运的是GCC和MSVC都提供了相应的机制实现main之前和之后调用函数。

​ 正好GCC提供了attribute关键字,可以通过声明constructor和destructor的函数,声明constructor的函数会在main函数之前调用,声明destructor函数会在main之后调用。

#include<stdio.h> 

// 声明一个constructor属性函数,此函数会在main之前运行
__attribute__((constructor)) void before() 
{  
   printf("run function before main\n"); 
} 

// 声明一个destructor属性函数,此函数会在main之后运行
__attribute__((destructor)) void after() 
{ 
   printf("run function after main\n"); 
} 
  
int main(int argc, char **argv) 
{ 
   printf("run main function\n"); 
   return 0; 
}

​ 结果表明,使用__attribute__关键词可以实现在main函数前运行语句,所以根据这个特性,我们可以实现GCC版本的饿汉单例版本。

案例

​ 结构声明

#pragma once

#include <stdio.h>
#include <stdlib.h>

typedef  void  File;

typedef enum BOOL
{
	FALSE = 0,
	TRUE = 1,
}BOOL;

typedef struct tagFileManager
{
	File* (*mkFile)(const char* fileName, char const* mode);
	BOOL  (*rmFile)(const char*  fileName);
	int   (*write)(File* file, const char* buf, int size);
	BOOL  (*exit)(const char* fileName);
	BOOL  (*close)(const File* file);
}FileManager;

实现说明

#include "file_manager.h"

#include <io.h>

static FileManager g_fileManager;

typedef int constructor();

static File* mkFile(const char* fileName, char const* mode);
static BOOL rmFile(const char* fileName);
static int fileWrite(File* file, const char* buf, int size);
static BOOL isExit(const char* fileName);
static BOOL fileClose(const File* file);

File* mkFile(const char* fileName, char const* mode)
{
	FILE* file = NULL;
	if (0 == fopen_s(&file, fileName, mode))
	{
		return file;
	}
	
	return NULL;
}

BOOL rmFile(const char* fileName)
{
	if (isExit(fileName))
	{
		return !remove(fileName);
	}
}

int fileWrite(File* file, const char* buf, int size)
{
	return fwrite(buf, size, 1, file);
}

BOOL isExit(const char* fileName)
{
	return (_access(fileName, 0) == 0);
}

BOOL fileClose(const File* file)
{
	return !fclose(file);
}

__attribute__((constructor)) static int ctor()
{
	g_fileManager.exit = isExit;
	g_fileManager.mkFile = mkFile;
	g_fileManager.rmFile = rmFile;
	g_fileManager.write = fileWrite;
	g_fileManager.close = fileClose;
	return 0;
}

__attribute__((destructor)) static int dtor()
{
	g_fileManager.exit = NULL;
	g_fileManager.mkFile = NULL;
	g_fileManager.rmFile = NULL;
	g_fileManager.write = NULL;
	g_fileManager.close = NULL;
	return 0;
}

FileManager* fileManager()
{
	return &g_fileManager;
}

标签:const,file,fileManager,模式,C语言,char,单例,fileName,main
From: https://www.cnblogs.com/Kroner/p/17535894.html

相关文章

  • Docker安装Nacos并以单例模式运行
    Nacos单例模式运行使用嵌入式数据库即可,这里不依赖于mysql。拉取指定版本Nacos镜像:dockerpullnacos/nacos-server:2.0.3查看镜像列表:dockerimages以单例模式启动:dockerrun-d--namenacos-p8848:8848-eMODE=standalonenacos/nacos-server:2.0.3查看容器列表......
  • 设计模式之类之间的关系和六大原则
    1类之间的关系类与类之间的关系大概有6种,要看懂UML图,首先需要了解这几种关系。1.1继承关系继承指的是一个类(称为子类,子接口)继承另外的一个类(成为父类,父接口)的功能,并可以增加它自己的新功能的能力。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或......
  • C++ 设计模式之建造者模式
    设计模式之建造者模式建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。其UML图如下:简单理解就是Builder中定义了创建Product各个部分的接口。ConcreteBuilder中具体实现了创建Product中的各个部分的接口,就是具体的建造者。Director......
  • C++设计模式之观察者模式
    设计模式之观察者模式观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。其UML图如下: 在ConcretSubject内部有一个Observer的列表,当Subject的状态发生改变时,会通知列表内......
  • C++ 设计模式之抽象工厂模式
    设计模式之抽象工厂模式抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。其UML图如下: 结合上图我们来理解一下抽象工厂模式的定义。提供一个创建一些列相关或相互依赖对象的接口,而无需指定它们具体的类。在上图中一系列相互依赖或相关......
  • C++ 设计模式之模板方法模式
    设计模式之模板方法模式模板方法模式,定义一个操作中的算法的股价,而将一些步骤延迟到了子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。说白了就是有一个算法有很多部分,这个算法在基类中已经定义好了。而算法中的各个部分都写成各个成员函......
  • JAVA设计模式之模板模式
    设计模式设计模式(DesignPattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、......
  • C++ 设计模式之备忘录模式
    设计模式之备忘录模式备忘录,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。该模式很好理解,其UML图如下:在Originator中提供了创建Memento的接口,具体要保存什么样的内容,则根据需求来定。而Caretake......
  • C++ 设计模式之责任链模式
    设计模式之责任链模式责任链模式,使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象练成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。该模式很好理解,其UML图如下: 每个ConcreteHandler都有一定的请求处理能力,当自己处理不了的时......
  • C++ 设计模式之中介者模式
    设计模式之中介者模式中介者模式,用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地互相引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。该模式很好理解,其UML图如下: Mediator中每个交互者的引用,在Mediator内部封装了各种类之间的交互。至于那个类......