6.8 KiB
6.8 KiB
使用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个模板函数
单例模式应用的场景一般发现在以下条件下:
- 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
- 控制资源的情况下,方便资源之间的互相通信。如线程池等。
- 只需一个存在就可以的情况
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 改进访问者模式
访问者模式需要注意的问题:定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重新定义对所有访问者的接口。
通过可变参数模板就可以实现一个稳定的接口层,可以让访问者的接口层访问任意个数的访问者,这样就不需要每增加一个新的被访问者就修改接口层,从而使接口层保证稳定。
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 改进命令模式
命令模式的作用是将请求封装成一个对象,将请求的发起者和执行者解耦,支持对请求排队、撤销和重做。由于将请求都封装成一个一个命令对象了,使得我们可以集中处理或者延迟处理这些命令请求,而且不同客户对象可以共享这些命令,还可以控制请求的优先权、排队、支持请求的撤销和重做。
缺点:越来越多的命令会导致类爆炸,难以管理
接收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;
};