250 lines
6.8 KiB
Markdown
250 lines
6.8 KiB
Markdown
|
### 使用c++11改进我们的模式
|
|||
|
### 8.1 改进单例模式
|
|||
|
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
|
|||
|
```
|
|||
|
#pragma once
|
|||
|
|
|||
|
template <typename T>
|
|||
|
class Singleton
|
|||
|
{
|
|||
|
public:
|
|||
|
template<typename... Args>
|
|||
|
static T* Instance(Args&&... args)
|
|||
|
{
|
|||
|
if(m_pInstance==nullptr)
|
|||
|
m_pInstance = new T(std::forward<Args>(args)...);
|
|||
|
|
|||
|
return m_pInstance;
|
|||
|
}
|
|||
|
|
|||
|
static T* GetInstance()
|
|||
|
{
|
|||
|
if (m_pInstance == nullptr)
|
|||
|
throw std::logic_error("the instance is not init, please initialize the instance first");
|
|||
|
|
|||
|
return m_pInstance;
|
|||
|
}
|
|||
|
|
|||
|
static void DestroyInstance()
|
|||
|
{
|
|||
|
delete m_pInstance;
|
|||
|
m_pInstance = nullptr;
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
Singleton(void);
|
|||
|
virtual ~Singleton(void);
|
|||
|
Singleton(const Singleton&);
|
|||
|
Singleton& operator=(const Singleton&);
|
|||
|
private:
|
|||
|
static T* m_pInstance;
|
|||
|
};
|
|||
|
|
|||
|
template <class T> T* Singleton<T>::m_pInstance = nullptr;
|
|||
|
```
|
|||
|
使用了可变参数与完美转发,避免了写N个模板函数
|
|||
|
|
|||
|
单例模式应用的场景一般发现在以下条件下:
|
|||
|
1. 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
|
|||
|
2. 控制资源的情况下,方便资源之间的互相通信。如线程池等。
|
|||
|
3. 只需一个存在就可以的情况
|
|||
|
### 8.2 改进观察者模式
|
|||
|
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都能得到通知并被自动更新。
|
|||
|
|
|||
|
```
|
|||
|
#pragma once
|
|||
|
class NonCopyable
|
|||
|
{
|
|||
|
public:
|
|||
|
NonCopyable(const NonCopyable&) = delete; // deleted
|
|||
|
NonCopyable& operator = (const NonCopyable&) = delete; // deleted
|
|||
|
NonCopyable() = default; // available
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
#include <iostream>
|
|||
|
#include <string>
|
|||
|
#include <functional>
|
|||
|
#include <map>
|
|||
|
using namespace std;
|
|||
|
|
|||
|
#include "NonCopyable.hpp"
|
|||
|
|
|||
|
template<typename Func>
|
|||
|
class Events : NonCopyable
|
|||
|
{
|
|||
|
public:
|
|||
|
//注册观察者,支持右值引用
|
|||
|
int Connect(Func&& f)
|
|||
|
{
|
|||
|
return Assgin(f);
|
|||
|
}
|
|||
|
|
|||
|
//注册观察者
|
|||
|
int Connect(const Func& f)
|
|||
|
{
|
|||
|
return Assgin(f);
|
|||
|
}
|
|||
|
//移除观察者
|
|||
|
void Disconnect(int key)
|
|||
|
{
|
|||
|
m_connections.erase(key);
|
|||
|
}
|
|||
|
|
|||
|
//通知所有的观察者
|
|||
|
template<typename... Args>
|
|||
|
void Notify(Args&&... args)
|
|||
|
{
|
|||
|
for (auto& it: m_connections)
|
|||
|
{
|
|||
|
it.second(std::forward<Args>(args)...);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
//保存观察者并分配观察者的编号
|
|||
|
template<typename F>
|
|||
|
int Assgin(F&& f)
|
|||
|
{
|
|||
|
int k=m_observerId++;
|
|||
|
m_connections.emplace(k, std::forward<F>(f));
|
|||
|
return k;
|
|||
|
}
|
|||
|
|
|||
|
int m_observerId=0;//观察者对应的编号
|
|||
|
std::map<int, Func> m_connections;//观察者列表
|
|||
|
};
|
|||
|
```
|
|||
|
### 8.3 改进访问者模式
|
|||
|
访问者模式需要注意的问题:定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重新定义对所有访问者的接口。<br>
|
|||
|
通过可变参数模板就可以实现一个稳定的接口层,可以让访问者的接口层访问任意个数的访问者,这样就不需要每增加一个新的被访问者就修改接口层,从而使接口层保证稳定。
|
|||
|
```
|
|||
|
template<typename... Types>
|
|||
|
struct Visitor;
|
|||
|
|
|||
|
template<typename T, typename... Types>
|
|||
|
struct Visitor<T, Types...> : Visitor<Types...>
|
|||
|
{
|
|||
|
using Visitor<Types...>::Visit;//通过using避免隐藏基类的visit同名方法
|
|||
|
virtual void Visit(const T&) = 0;
|
|||
|
};
|
|||
|
|
|||
|
template<typename T>
|
|||
|
struct Visitor<T>
|
|||
|
{
|
|||
|
virtual void Visit(const T&) = 0;
|
|||
|
};
|
|||
|
```
|
|||
|
### 8.4 改进命令模式
|
|||
|
命令模式的作用是将请求封装成一个对象,将请求的发起者和执行者解耦,支持对请求排队、撤销和重做。由于将请求都封装成一个一个命令对象了,使得我们可以集中处理或者延迟处理这些命令请求,而且不同客户对象可以共享这些命令,还可以控制请求的优先权、排队、支持请求的撤销和重做。<br>
|
|||
|
缺点:越来越多的命令会导致类爆炸,难以管理<br>
|
|||
|
接收function、函数对象、lambda和普通函数的包装器:
|
|||
|
```
|
|||
|
template<class F,class... Args,class=typename std::enable_if<!std::is_member_function_pointer<F>::value>::type>
|
|||
|
void Wrap(F&& f, Args && ...args)
|
|||
|
{
|
|||
|
return f(std::forward<Args>(args)...);
|
|||
|
}
|
|||
|
```
|
|||
|
接收成员函数的包装器:
|
|||
|
```
|
|||
|
template<class R,class C,class... DArgs,class P,class... Args>
|
|||
|
void Wrap(R(C::*f)(DArgs...),P&& p,Args&& ... args)
|
|||
|
{
|
|||
|
return; (*p.*f)(std::forward<Args>(args)...);
|
|||
|
}
|
|||
|
```
|
|||
|
```
|
|||
|
#include <functional>
|
|||
|
#include <type_traits>
|
|||
|
template<typename Ret = void>
|
|||
|
struct CommCommand
|
|||
|
{
|
|||
|
private:
|
|||
|
std::function < Ret()> m_f;
|
|||
|
|
|||
|
public:
|
|||
|
//接受可调用对象的函数包装器
|
|||
|
template< class F, class... Args, class = typename std::enable_if<!std::is_member_function_pointer<F>::value>::type>
|
|||
|
void Wrap(F && f, Args && ... args)
|
|||
|
{
|
|||
|
m_f = [&]{return f(args...); };
|
|||
|
}
|
|||
|
|
|||
|
//接受常量成员函数的函数包装器
|
|||
|
template<class R, class C, class... DArgs, class P, class... Args>
|
|||
|
void Wrap(R(C::*f)(DArgs...) const, P && p, Args && ... args)
|
|||
|
{
|
|||
|
m_f = [&, f]{return (*p.*f)(args...); };
|
|||
|
}
|
|||
|
|
|||
|
//接受非常量成员函数的函数包装器
|
|||
|
template<class R, class C, class... DArgs, class P, class... Args>
|
|||
|
void Wrap(R(C::*f)(DArgs...), P && p, Args && ... args)
|
|||
|
{
|
|||
|
m_f = [&, f]{return (*p.*f)(args...); };
|
|||
|
}
|
|||
|
|
|||
|
Ret Excecute()
|
|||
|
{
|
|||
|
return m_f();
|
|||
|
}
|
|||
|
};
|
|||
|
```
|
|||
|
### 8.5 改进对象池
|
|||
|
```
|
|||
|
#include <string>
|
|||
|
#include <functional>
|
|||
|
#include <memory>
|
|||
|
#include <map>
|
|||
|
#include "NonCopyable.hpp"
|
|||
|
using namespace std;
|
|||
|
|
|||
|
const int MaxObjectNum = 10;
|
|||
|
|
|||
|
template<typename T>
|
|||
|
class ObjectPool : NonCopyable
|
|||
|
{
|
|||
|
template<typename... Args>
|
|||
|
using Constructor = std::function<std::shared_ptr<T>(Args...)>;
|
|||
|
public:
|
|||
|
//默认创建多少个对象
|
|||
|
template<typename... Args>
|
|||
|
void Init(size_t num, Args&&... args)
|
|||
|
{
|
|||
|
if (num<= 0 || num> MaxObjectNum)
|
|||
|
throw std::logic_error("object num out of range.");
|
|||
|
|
|||
|
auto constructName = typeid(Constructor<Args...>).name(); //不区分引用
|
|||
|
for (size_t i = 0; i <num; i++)
|
|||
|
{
|
|||
|
m_object_map.emplace(constructName, shared_ptr<T>(new T(std::forward<Args>(args)...), [this, constructName](T* p) //删除器中不直接删除对象,而是回收到对象池中,以供下次使用
|
|||
|
{
|
|||
|
m_object_map.emplace(std::move(constructName), std::shared_ptr<T>(p));
|
|||
|
}));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//从对象池中获取一个对象
|
|||
|
template<typename... Args>
|
|||
|
std::shared_ptr<T> Get()
|
|||
|
{
|
|||
|
string constructName = typeid(Constructor<Args...>).name();
|
|||
|
|
|||
|
auto range = m_object_map.equal_range(constructName);
|
|||
|
for (auto it = range.first; it != range.second; ++it)
|
|||
|
{
|
|||
|
auto ptr = it->second;
|
|||
|
m_object_map.erase(it);
|
|||
|
return ptr;
|
|||
|
}
|
|||
|
|
|||
|
return nullptr;
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
multimap<string, std::shared_ptr<T>> m_object_map;
|
|||
|
};
|
|||
|
```
|