设计模式的六大原则
(1)几种设计原则的小结(6个原则的首字母组合单词(S.O.L.I.D,表示稳定)
①单一职责原则告诉我们实现类要职责单一;
②里氏替换原则告诉我们不要破坏继承体系;所有使用基类的地方必须能透明地使用子类替换,而程序的行为没有任何变化
③依赖倒置原则告诉我们要面向接口编程;
④接口隔离原则告诉我们在设计接口的时候要精简单一;
⑤迪米特法则告诉我们要降低耦合。
⑥开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。
(2)建立稳定、灵活、健壮的设计,开闭原则是最基础的原则,也是精神领袖
(3)开闭原则是最基础的一个原则,前五个原则都是开闭原则的具体形态,而开闭原则才是灵魂。换一个角度,借用OOP的说法,开闭原则是抽象类,其他五大原则是具体的实现类。
单例模式
(1)懒汉式:
①其特点是延迟加载,典型的以“时间换空间”做法。即只会在全局访问方法首次被调用时才被创建。
②问题:new出来的实例不能自动释放,可能存在内存泄漏问题。其解决方法有2种。
A.方法1:在单例类内部定义专有的嵌套类,并在单例类定义一个私有的专门用于释放的静态成员,当程序结束析构全局变量时,会自动调用并释放这个单例。
B.方法2:在单例类提供一个专门用于释放的静态成员函数,并在需要时手动释放。
③在实际项目中,单例一般是个全局变量,它的生命期随软件运行结束而自然终止。也就没有内存泄漏,但是如果单例中用到了一个文件锁、文件句柄或数据库连接,这些并不会随程序的关闭而立即关闭,必须在程序关闭前进行手动释放。
代码-懒汉式B
#include <iostream>
using namespace std;
class singleton{
protected:
singleton(){} //为了防止在外部调用类的构造函数而创建实例,需要将构造函数的访问权限设为protected或private;
singleton(const singleton&other){};
singleton& operator=(const singleton&other){}; //单例类一般不会主动要求被复制的,因此复制构造函数和赋值构造函数一般也设为私有。
private:
static singleton *p;
public:
static singleton *instance(); //全局访问点
static void clearinstance();
};
singleton* singleton::p = NULL;
singleton* singleton::instance()
{
if (p == NULL)
{
cout << "开始创建实例" << endl;
p = new singleton();
return p;
}
return p;
}
void singleton::clearinstance()
{
if (p != NULL)
{
cout << "执行删除操作" << endl;
delete p;
p = NULL;
}
}
int main()
{
singleton *p1 = singleton::instance();
singleton *p2 = p1->instance();
singleton *p3 = singleton::instance();
printf("p1 = %p\n", p1);
printf("p2 = %p\n", p2);
printf("p3 = %p\n", p2);
p1->clearinstance();
p2->clearinstance();
return 0;
}
结果
代码-懒汉式A
在单例类内部定义专有的嵌套类,并在单例类定义一个私有的专门用于释放的静态成员,当程序结束析构全局变量时,会自动调用并释放这个单例。
class sigleton{
private:
sigleton(){}
sigleton(const sigleton& other){}
sigleton& operator=(const sigleton& other){}
static sigleton* instance;
class GC{
public:
~GC(){
if (instance != NULL)
{
cout << "执行删除操作" << endl;
delete instance;
instance = NULL;
}
}
};
public:
static sigleton* getinstance();
static GC gc;
};
sigleton* sigleton::getinstance()
{
if (instance == NULL)
{
cout << "执行创建实例" << endl;
instance = new sigleton();
return instance;
}
return instance;
}
sigleton* sigleton::instance = NULL;
sigleton::GC sigleton::gc;
int main()
{
sigleton* p1 = sigleton::getinstance();
sigleton* p2 = p1->getinstance();
sigleton* p3 = sigleton::getinstance();
printf("p1 = %p\n", p1);
printf("p2 = %p\n", p2);
printf("p3 = %p\n", p2);
return 0;
}
结果
(2)饿汉式
其特点是一开始就加载了,典型的“空间换时间”作法。因为一开始就创建了实例,所以每次用时直接返回就好了.
//创建型模式:单例模式
#include <stdio.h>
//饿汉式:多线程安全
class CSingleton
{
public:
//提供全局访问的访问点
static CSingleton* getInstance()
{
//cout << "执行创建操作"<<endl;
static CSingleton instance;
return &instance;
}
private:
//将构造函数设为私有属性
CSingleton(){};
};
int main()
{
CSingleton* s1 = CSingleton::getInstance();
CSingleton* s2 = CSingleton::getInstance();
printf("s1 = %p\n", s1);
printf("s2 = %p\n", s2);
return 0;
}
双重锁
线程安全
class Lock
{
private:
HANDLE m_hMutex;
public:
Lock()
{
m_hMutex = CreateMutex(NULL, false, NULL);//安全性,true创建线程立刻获得所有权,匿名
}
~Lock(){CloseHandle(m_hMutex);}
void lock(){ WaitForSingleObject(m_hMutex,INFINITE); }
void unlock(){ ReleaseMutex(m_hMutex); }
};
class singleton{
private:
singleton(){}
static singleton* instance; //声明
static Lock m_lock; //锁成为静态变量 声明
public:
static singleton* getInstance()
{
if (instance == NULL)
{
m_lock.lock();
if (instance == NULL)
{
instance = new singleton();
}
m_lock.unlock();
}
return instance;
}
};
singleton* singleton::instance = NULL; //定义初始化
Lock singleton::m_lock; //定义
DWORD WINAPI ThreadProc(PVOID pvParam)
{
singleton* s = singleton::getInstance();
printf("thread:%d, address = %p\n", (int)pvParam, s);
Sleep(1000);
return 0;
}
int main()
{
const int iCount = 64;
HANDLE hThread[iCount];
for (int i = 0; i < iCount; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadProc, (LPVOID)i, 0, NULL);
//安全性,初始栈大小,线程处理函数,传递参数,线程创建标记,线程id
}
//注意:WaitForMultipleObjects最多能等待64个内核对象
WaitForMultipleObjects(iCount, hThread, TRUE, INFINITE);
for (int i = 0; i < iCount; i++)
CloseHandle(hThread[i]);
return 0;
}
单例模式的使用场景
(1)多线程之间共享一个资源或者操作同一个对象
(2)在整个程序空间中使用全局变量,共享资源
(3)在创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源。
(4)大规模系统中,为了性能的考虑,需要节省对象的创建时间
(5)要求生成唯一序列号的环境或用单例做为一个计数器。