BlueRoseNote/02-Note/读书笔记/深入应用C++11代码优化与工程级应用/深入应用c++11代码优化与工程级应用第八章.md
2023-06-29 11:55:02 +08:00

6.8 KiB
Raw Blame History

使用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 改进访问者模式

访问者模式需要注意的问题:定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重新定义对所有访问者的接口。
通过可变参数模板就可以实现一个稳定的接口层,可以让访问者的接口层访问任意个数的访问者,这样就不需要每增加一个新的被访问者就修改接口层,从而使接口层保证稳定。

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;
};