设计模式(4)-序列生成器之单例模式

场景:序列生成器

系统中统一的序列生成程序,整个系统统一一套!那么就用单例模式吧!

首先看看单例模式

1)类持有一个自己的实例,而且还是个静态实例。

2)类的构造函数为私有属性。

3)用以获得实例的方法为静态方法。

看看类图


然后看一段试例程序:

#include <iostream>

using namespace std;

class Singleton{
private:
 Singleton();//注意:构造方法私有
 virtual ~Singleton();
 static Singleton* instance;//惟一实例
 int var;//成员变量(用于测试)
public:
 static Singleton* GetInstance();//工厂方法(用来获得实例)
 int getVar();//获得var的值
 void setVar(int);//设置var的值
};
//构造方法实现
Singleton::Singleton()
{
 this->var = 20;
 cout<<"Singleton Constructor"<<endl;
}
Singleton::~Singleton()
{
 if(instance != NULL)
 {
 delete instance;
 }
}
//初始化静态成员
//Singleton* Singleton::instance=new Singleton();
Singleton* Singleton::instance=NULL;
Singleton* Singleton::GetInstance()
{
 if(instance == NULL)
 {
 instance = new Singleton();
 }
 return instance;
}
//seter && getter含数
int Singleton::getVar()
{
 return this->var;
}
void Singleton::setVar(int var)
{
 this->var = var;
} 

int main(int argc, char* argv[])
{
 Singleton *ton1 = Singleton::GetInstance();
 Singleton *ton2 = Singleton::GetInstance();
 cout<<"ton1 var = "<<ton1->getVar()<<endl;
 ton1->setVar(150);
 cout<<"ton2 var = "<<ton2->getVar()<<endl;
 return 0;
}

1、构造方法私有

那么,就意味着,只能在Singleton的成员函数中,才能调用Singleton的构造函数来创建实例。在Singleton之外,不能创建Singleton对象的实例。

2、代码中,定义了GetInstance方法,只能通过GetInstance方法来获取Singleton对象的实例,单例就是在GetInstance方法中控制的。

首先,Singleton有一个
static Singleton* instance;//惟一实例

Singleton* Singleton::instance=NULL;
在这里初始化为NULL。

Singleton* Singleton::GetInstance()
{
if(instance == NULL)
{
instance = new Singleton();
}
return instance;
}

上面的函数,就是通过instance来实现单例的。

当第一次调用GetInstance时,instance 为NULL,所以会执行
instance = new Singleton();
把这个新建的实例保存到静态成员instance,并返回这个指针。

第二次到第N次调用GetInstance时,由于instance不为空,所以会直接返回instance 。也就是第一次调用GetInstance创建的那个实例。

所以这样就实现了,单实例。

意思就是说,Singleton对象的实例,只会被创建一次,就是说内存中,只存在一个Singleton的实例,就是所谓,单实例。

弄个生成单例的实例程序吧!

#include <sys/sem.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <iostream> 

using namespace std; 

#define MAXID 9999
static struct sembuf op_open={1,-1,0 };

class GenHH{
 private:
 GenHH();//注意:构造方法私有
 virtual ~GenHH();
 static GenHH* instance;//惟一实例
 int opensem(key_t semkey);
 int creatsem(key_t semkey,int bigcount);
 int sem_open(int semid);
 unsigned int gen_seq();
 public:
 static GenHH* getInstance();//工厂方法(用来获得实例)
 unsigned int gen_hh();
}

GenHH::~GenHH()
{
 if(instance != NULL)
 {
 delete instance;
 }
}

//初始化静态成员
GenHH* GenHH::instance=NULL;
GenHH* GenHH::getInstance()
{
 if(instance == NULL)
 {
 instance = new Singleton();
 }
 return instance;
}

unsigned int GenHH::gen_hh()
{
 unsigned int hh;
 char chh[9];

 memset(chh,0,9);

 sprintf(chh,"%05d%04d",time(NULL)%100000,gen_seq());

 hh = atoi(chh);

 return hh;
}

unsigned int GenHH::gen_seq()
{
 int seq,kid;
 int semid,semval;

 struct timeval tv;

 union semun {
 int val;
 struct semid_ds *buf;
 unsigned short *array;
 } semctl_arg;

 kid=ftok("/etc/hosts",'m');
 if(kid<0){
 printf("system Error! Can't find /etc/hosts!\n");
 gettimeofday(&tv, NULL);
 return tv.tv_usec % MAXID ;
 }

 semid=opensem(kid);
 if(semid<=0){
 semid=creatsem(kid,MAXID);
 if(semid<0){
 gettimeofday(&tv, NULL);
 return tv.tv_usec % MAXID ;
 }
 }

 semval=semctl(semid,1,GETVAL,0);
 if(semval<=2){
 semctl_arg.val=MAXID;
 if ((semctl(semid,1,SETVAL,semctl_arg)) < 0 ){
 gettimeofday(&tv, NULL);
 return tv.tv_usec % MAXID ;
 }
 }

 sem_open(semid);
 semval=semctl(semid,1,GETVAL,0);

 return MAXID-semval;
}

int GenHH::opensem(key_t semkey)
{
 int semid;

 semid=semget(semkey,2,0);
 if(semid<0){
 printf("semaphoreid get error!\n");
 return -1;
 }

 return semid;
}

int GenHH::creatsem(key_t semkey,int bigcount)
{
 int semid,semval;
 union semun {
 int val;
 struct semid_ds *buf;
 unsigned short *array;
 } semctl_arg;

 semid=semget(semkey,2,IPC_CREAT|0600);
 if(semid<0){
 return -1;
 }

 if((semval=semctl(semid,1,GETVAL,0))<0)
 printf("GETVAL error!\n");
 else if(semval==0){
 semctl_arg.val=1;
 if(semctl(semid,0,SETVAL,semctl_arg)<0)
 printf("SETVAL error\n");

 semctl_arg.val=bigcount;
 if(( semctl(semid,1,SETVAL,semctl_arg)) < 0 )
 printf("setval error\n");
 }

 return semid;
}

int GenHH::sem_open(int semid)
{
 while(( semop(semid,&op_open,1) ) < 0 ){
 if( errno==EINTR ) {
 usleep(5000);
 continue;
 }
 printf("sem op_open error!\n");
 return -1;
 }
 return 0;
}

int main(int argc, char* argv[])
{
 GenHH *genHH1 = GenHH::getInstance();
 GenHH *genHH2 = GenHH::getInstance();

 cout<<genHH1->gen_hh()<<endl;
 cout<<genHH2->gen_hh()<<endl;
 return 0;
}
时间: 2024-12-24 08:30:21

设计模式(4)-序列生成器之单例模式的相关文章

PHP设计模式之工厂模式与单例模式_php技巧

本文实例讲述了PHP设计模式之工厂模式与单例模式实现方法.分享给大家供大家参考,具体如下: 设计模式简单说应对某类问题而设计的解决方式 工厂模式:应对需求创建相应的对象 class factory{ function __construct($name){ if(file_exists('./'.$name.'.class.php')){ return new $name; }else{ die('not exist'); } } } 单例模式:只创建一个对象的实例,不允许再创建实例,节约资源(

SQL SERVER2005的序列生成方法

此外,真正要解决这个问题,还源于我做的试剂耗材的管理系统.以往生成条码为了保证唯一性,使用日期时间+序列的方式,为了保证它不重复,时间就取的很细,到了毫秒级别.虽然理论上来讲这仍然有重复的可能性. 其实重复毕竟是小概率,但是条码却太长了,比如一个试剂的条码是20140801162430234001,这么一大串,一来不容易被条码枪识别,二来即便识别也容易造成识别前半部分.如果实在没有识别要手输的话,就是要费很大的工夫了. 条码本来就是类似数据库主键的意味,只要保证不重复,就该越短越好. 既然sql

设计模式的C++实现之单例模式

单例模式,顾名思义,就是只能由一个实例,那么我们就必须保证 该类不能被复制. 该类不能被公开的创造 . 那么对于C++来说,他的构造函数,拷贝构造函数和他的赋值函数都不能被公开调用. 但对于该私有的构 造函数的构造时机上来说也可以分两种情况来构造: 只有当需要改类的时候去构造(即为懒汉模式) 在程序开始 之前我就先构造好,你到时候直接用就可(即为饿汉模式) 那么我分别来说说这两种模式: 懒汉模式,静态 局部变量只会被初始化一次即第一次执行的时候,其生命周期与程序的生命周期是相同的.这个同样适用于

《设计模式》学习笔记5——单例模式【高并发拓展】

定义 单例模式又称为单件模式,这个模式大概是设计模式中最好理解的了,我起初就打算从这里开始学,甚至还记过另一篇单例模式学习的笔记. 但是之后跟着<设计模式>这本书系统的学,就索性从第一页开始,而单例模式算是复习,也算是再深入的理解一次. 之所以要这么做,是因为上一次写的没有给出更标准的定义,同时,当时只介绍了基础的懒汉式和饿汉式,对于并发时候的单例却没有涉及,所以这篇学习的重点应当在于高并发时如何保证我们的单例依旧是单例. 单例模式引用书中的定义如下: 单例模式(Singleton Patte

PostgreSQL 空间、多维 序列 生成方法

标签 PostgreSQL , GIS , PostGIS , 序列 , 空间序列 背景 数据库的一维序列是很好理解的东西,就是在一个维度上自增. 那么二维.多维序列怎么理解呢?显然就是在多个维度上齐头并进的自增咯. 二维序列 以二维序列为例,应该是这样增长的: 0,0 0,1 1,0 1,1 1,2 2,1 2,2 ... 那么如何生成以上二维序列呢?实际上可以利用数据库的多个一维序列来生成. create sequence seq1; create sequence seq2; create

【java设计模式初探0】_单例模式

在java的几十种设计模式中,可能单例模式算是最容易理解的吧!因为不论是目前的我自己,还是偶尔面试的别人,能稍微讲清楚的,基本就是单例模式.什么叫单例模式?顾名思义,就是单一的实例,唯一的实例.也就是说对于某个java类来说,他的实例对象最多只能创建一个. 那么,稍微有点java基础的同学都知道,我们自己创建对象最基本的方式就是使用new关键字,通过类定义的构造器来创建.就比如有这样一个类: public class Earth{ public Earth(){ } } 我们自己创建该类的对象,

java学习:Hibernate学习-用oracle sequence序列生成ID的配置示例

接上回继续,TMP_EMP中的ID是根据序列SQ_TMP_EMP来生成的,需要在TmpEmp.hbm.xml中设置:   <id name="id" type="long">   <column name="ID" not-null="true" sql-type="NUMBER" unique="true"/>   <generator class=&qu

根据前序和中序序列生成二叉树

一.前言: 我的一个同事拿来她老公的远程教育的考试题,叫大家帮着做,我写了这道,源码通过VC6编译链接,执行成功,呵呵:)题目就是给出了一个二叉树的前序序列(ABDCEGF)和中序序列(DBAEGCF),要求根据这两个输入完成一个二叉树,但没有指定用什么方式,所以我用了最笨拙的顺序存储二叉树,不过用了map来保存二叉树.题目还要求形成二叉树后可以遍历这个二叉树,由于三种遍历只是顺序不同,所以我只实现了后序遍历,何况输入就是前序和中序.:)本来应该用template做的,不过同事要求不要用复杂的C

全自动静态网页生成器之缘起及html文件解析

见过太多的大网站都已使用了静态网页.从性能上考虑,这当然是这类网站不二选择.虽然一直以来都很希望能够实现这个功能,但是毕竟没有很急切的需求,所以一直搁置下来.终于,现在的一个项目决定使用静态网页生成技术,我也狠下心来解决这个问题. 曾经思考过很多种方案,但是一一否决了.一种方案是使用XML方案,从CSDN剽窃过来的思路,用XML文件保存数据,然后定义一个XSL,在客户端解析.这种方案最大的缺点是无法处理复杂的页面布局.设想一个很复杂的页面,你很难定义出合适的XSL,而且在客户端的开销也可能不被接