单例模式(singleton)
保证一个类只有一个实例存在,提供对该实例加以访问的全局访问方法
实现:
- 构造函数私有化
防止别的地方调用 - 提供一个全局的静态方法
- 类中有一个静态指针,指向该类类型
让类负责保存他唯一的实例。
这里隐含的含义是,程序知道这个类只能被这样实例化。
代码
// ./Singleton.h
class Singleton
{
private:
Singleton()=default;
static Singleton *_instance;
public:
static Singleton *instance();
static bool freeInstance();
}
// ./Singleton.cc
#include "Singleton.h"
//惰性模式,不访问不创建,在第一次访问的时候创建
//对静态变量的初始化必需放在类的外部
Singleton Singleton::*_instance=nullptr;
Singleton Singleton::*instance()
{
if(_instance=nullptr)
{
_instance = new Singleton();
}
return _instance;
}
//
//非惰性模式
//在程序一运行就进行了初始化
Singleton Singleton::*_instance=new Singleton();
Singleton Singleton::*instance()
{
return _instance;
}
//
bool Singleton::freeInstance()
{
if(_instance!=nullptr)
{
delete _instance;
_instance=nullptr;
}
}
使用
#include "Singleton.h"
int main()
{
Singleton *p=Singleton::instance();
//....
return 0;
}
单例模式与多线程
惰性单例模式由于其实例初始化的方式,会导致在多线程中可能创建多个实例,所以其构造函数不是一种线程安全的函数。
因此如果使用惰性模式,需要使用互斥量。
"单例"模式
单例模式的类,可以不止有一个实例,如果一个类需要几个特定类型,或者需要的某种类型的实例的数量只需要一个。
那么可以不使用_instance
存储,改为map<string,Singleton*>
即可。
建造者模式
对象的构建太复杂
将对象的表示与构建分离
例如,有一些类在创建的时候,需要传大量的参数,还可能某一下参数是选填的。
并且还可能,这个类的实例创建出来以后,还有一些字段需要填。
那么如果只是用构造函数,那么这个逻辑,这个构造函数,可能会很臃肿。
也有一些字段可能就那么几种,也就是说有那么一个模板。
啥?你说怎么可能有这样的类?
人员管理啊,名字,地址,联系方式,这些是必填的选项吧。邮箱,老婆,女朋友,这些事选填的吧。万一以后又要加上工资这个字段,咋办?还是用构造函数?
不现实啊。
设计模式是将问题的解决方法标准化的方法,再加上解耦,这个本来就复杂的问题,变得更加复杂了。嗯~~
UML
代码
//人员
class ClerkDetail
{
public:
clerkDetail()=default;
clerkDetail(string name); //表示必填的字段
string sex(); //下面的是字段的设置和获取选项,使用了重载。
void sex(string s);
int age();
void age(int i);
private:
string _name;
string _sex; //下面两个表示选填的字段
int _age;
};
//模板继承的基类
class abClerkTplt
{
virtual void sex(); //这两个是抽象的借口,t他们没有参数
virtual void age(); //因为其子类,将根据子类所指示的那种模板设置参数。
virtual ClerkDetail* getclerk();
};
//人员的一些模板
class ManClerk:pubilc:abClerkTplt
{
public:
ManClerk()
{
_clerk=new ClerkDetail;
}
virtual void sex()
{
_clerk->set("man");
}
virtual void age()
{
_clerk->age(17);
}
virtual ClerkDetail* getclerk()
{
return _clerk;
}
private:
ClerkDetail *_clerk;
};
//人员的一些模板,这里还是一个模板
class WomanClerk:pubilc:abClerkTplt
{
//....
};
//一个执行模板子类的类。
class createClerk
{
public:
createClerk(abClerkTplt* Tplt)
{
_tplt=tplt;
}
vodi create()
{
tplt->age();
tplt->sex();
}
private:
abClerkTplt* _tplt;
};
//使用
int main()
{
abClerkTplt* manTplt=new ManClerk;
createClerk dir(manTplt);
dir.crete();
ClerkDetail *clerk1=manTplt->getClerk();
}
这个模式过于复杂。应该是可以简化的吧。比如createClerk
这个类,应该可以去掉吧。
以后再想想。
原型模式
类能够提供一个能够复制自身的接口
复制自身则涉及到深拷贝和浅拷贝。
在复制指针类型时,如果之复制指针那么就是浅拷贝:两个指针指向相同的地址,容易造成二次释放。(多次释放同一块内存的地址)
复制指针的时候,复制指针复制地址的内容,在内存中开辟新的内存空间,而不是复制指针内容,称为深拷贝:没啥问题。
浅拷贝好比复制顶层。而深拷贝复制底层。
原型模式时,类自身提供一个clone()
接口,返回自身类型的指针。就这么简单
复制的时候,要么使用默认构造函数,创建一个临时对象,要么使用拷贝构造函数。
UML
代码
class AbPerson
{
public:
virtual AbPerson *clone()=0;
}
class Clerk:public:AbPerson
{
public:
Clerk();
Clerk(&clerk c)
{
//这里可以直接复制的就直接复制
i=this.i;
//c因为是个指针。不能够直接复制,需要分配内存。
c=this.cloneC();
}
virtual AbPerson *clone()
{
//转发给拷贝构造函数,让拷贝构造函数干活
return new Clerk(*this)
}
private:
int i;
char *c;
char *cloneC()//这里可以放一个函数,用来复制C,有几个指针,就有几个这种函数。
{
}
}
这一部分回头看看书。。。深拷贝+拷贝构造函数有点蒙了。
既然有了拷贝构造函数,那么为什么还需要原型模式?
拷贝构造函数只能复制自身。
而原型模式的基类提供了一种可以复制自身的方法,并且返回基类的指针。
拷贝构造函数为原型模式提供了实现。
享元模式
使用共享对象可有效的支持大量细粒度的对象
享元模式:共享不变的那部分元素。
如果系统需要创建大量的元素,而这些元素某一部分特征又是相同的,另一部分与有自己的特征。
比如,别人都提到的文本编辑器,每个字符可共享的部分就是字符本身,特征部分是字符的字号,颜色。
比如黑白棋,棋子可共享,但是有黑白和位置之分。
享元模式将一个对象划分为可变部分和不可变部分,该类型对象的数量并没介绍反而增加了。但是系统中总的对象数量确实是减少了。程序所占内存减少。