记录篇-C++11应用-改进模式

前言

本文是记录个人对c++11读写相关的学习,文中所用可能会采用其他大神的图、思路、例子等,请大神们见谅。本博客文章是在学习过程的一些总结,整理出来,分享给大家,希望对各位读者有帮助,文章中的总结可能存在很多不完整或有错误的地方,也希望读者指出。

1、改进单例模式

通过创建单例的模板函数来实现

template <typename T>
class Singleton
{
public: 
	//支持0个参数的构造函数
	static T* Instance()
	{
		if(m_pInstance == nullptr)
			m_pInstance = new T();

		printf("0pram contruct\n");
		return m_pInstance;
	}

	//支持1个参数的构造函数
	template <typename T0>
	static T* Instance(T0 arg0)
	{
		if(m_pInstance == nullptr)
			m_pInstance = new T(arg0);

		printf("1pram contruct\n");
		return m_pInstance;
	}

	//支持2个参数的构造函数
	template <typename T0, typename T1>
	static T* Instance(T0 arg0, T1 arg1)
	{
		if(m_pInstance == nullptr)
			m_pInstance = new T(arg0, arg1);
		printf("2pram contruct\n");
		return m_pInstance;
	}

	template <typename T0, typename T1, typename T2>
	static T* Instance(T0 arg0, T1 arg1, T2 arg2)
	{
		if(m_pInstance == nullptr)
			m_pInstance = new T(arg0, arg1, arg2);

		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;

struct A
{
	A(){}
};

struct B
{
	B(int x){}
};

struct C
{
	C(int x, double y){}
};

int main()
{
	Singleton<A>::Instance();
	Singleton<B>::Instance(1);
	Singleton<C>::Instance(1, 3.14);

	Singleton<A>::DestroyInstance();
	Singleton<B>::DestroyInstance();
	Singleton<C>::DestroyInstance();
}

总结:可以看出有着很多重复的模板定义,而且随着参数的增多,模板个数也不不断增多,不灵活且不简洁

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;
struct A
{
	A(const string&){cout<<"lvaue"<<endl;}
	A(string&& x){cout<<"rvaue"<<endl;}
};

struct B
{
	B(const string&){cout<<"lvaue"<<endl;}
	B(string&& x){cout<<"rvaue"<<endl;}
};

struct C
{
	C(int x, double y){}
	void Fun(){cout<<"test"<<endl;}
};

int main()
{
	string str = "bb";
	Singleton<A>::Instance(str); //创建A类型的单例
	Singleton<B>::Instance(std::move(str));//创建B类型的单例,临时变量str被move之后变成了右值,然后才可以根据移动语义来避免复制
	Singleton<C>::Instance(1, 3.14);
	Singleton<C>::GetInstance()->Fun();

	Singleton<A>::DestroyInstance();
	Singleton<B>::DestroyInstance();
	Singleton<C>::DestroyInstance();
}

总结:没有重复的模板的定义,支持任意个参数类型的创建,支持完美转发。能够将左值或者右值转发到对应的构造函数种,通过右值引用的移动还能进一步提升性能

2、改进观察者模式

1)简单的观察者模式实现
Observer.h

class Observer
{
public:
    Observer() {};
    virtual ~Observer() {};
    // 定义纯虚函数,规范接口
    virtual void update() = 0;
};

Subject.h

#include <vector>

using namespace std;
class Observer;
class Subject
{
public:
    Subject() {};
    virtual ~Subject() {};
    void addObserver(Observer *observer);
    void deleteObserver(Observer *observer);
    void notifyObservers();
    virtual int getStatus() = 0;
    virtual void setStatus(int status) = 0;
private:
    std::vector<Observer*> m_observers;
};

Subject.cpp

#include "Subject.h"
#include "Observer.h"

void Subject::addObserver(Observer *observer)
{
    m_observers.push_back(observer);
}

void Subject::deleteObserver(Observer * observer)
{
    for (vector<Observer*>::iterator iter = m_observers.begin();
        iter != m_observers.end(); iter++)
    {
        if (*iter == observer)
        {
            m_observers.erase(iter);
            return;
        }
    }
}

void Subject::notifyObservers() {
    for (vector<Observer*>::iterator iter = m_observers.begin();
        iter != m_observers.end();
        iter++)
    {
        (*iter)->update();
    }
}

ConcreteSubject.h

#include <string>
#include "Subject.h"

using namespace std;
class ConcreteSubject : public Subject
{

public:
    ConcreteSubject(string name) :m_subjectName(name) {};
    ~ConcreteSubject() {};

    void setStatus(int status);
    int getStatus();

private:
    string m_subjectName;
    int m_status = 0;
};

ConcreteSubject.cpp

#include <iostream>
#include "ConcreteSubject.h"

using namespace std;

void ConcreteSubject::setStatus(int status)
{
    m_status = status;
    cout << "setStatus subject[" << m_subjectName << "] status:" << status << endl;
}

int ConcreteSubject::getStatus()
{
    return m_status;
}

ConcreteObserver.h

#include <string>
#include "Observer.h"

class Subject;
using namespace std;

class ConcreteObserver:public Observer
{
public:
    ConcreteObserver(string name, Subject *subject) :m_observerName(name), m_subject(subject) {};
    ~ConcreteObserver() {};
    void update();

private:
    string m_observerName;
    Subject *m_subject;
};

ConcreteObserver.cpp

#include <iostream>
#include "ConcreteObserver.h"
#include "Subject.h"
using namespace std;

void ConcreteObserver::update()
{
    cout << "update observer[" << m_observerName << "] status:" << m_subject->getStatus() << endl;
}

main.cpp

#include <iostream>
#include "ConcreteObserver.h"
#include "ConcreteSubject.h"

int main(int argc, char *argv[])
{
    Subject * subjectA = new ConcreteSubject("subjectA");
    Subject * subjectB = new ConcreteSubject("subjectB");

    Observer * observerA = new ConcreteObserver("observerA", subjectA);
    Observer * observerB = new ConcreteObserver("observerB", subjectB);

    subjectA->addObserver(observerA);
    subjectB->addObserver(observerB);

    subjectA->setStatus(1);
    subjectA->notifyObservers();

    subjectB->setStatus(2);
    subjectB->notifyObservers();

    cout << "--------------------" << endl;


    subjectA->addObserver(observerB);
    subjectA->setStatus(2);
    subjectA->notifyObservers();

    delete subjectA;
    delete subjectB;
    delete observerA;
    delete observerB;

    return 0;
}

makefile

# 方便起见一般都会先定义编译器链接器
CC = g++
LD = g++

# 正则表达式表示目录下所有.c文件,相当于:SRCS = main.c a.c b.c
SRCS = $(wildcard *.cpp)

# OBJS表示SRCS中把列表中的.c全部替换为.o,相当于:OBJS = main.o a.o b.o
OBJS = $(patsubst %cpp, %o, $(SRCS))

# 可执行文件的名字
TARGET = test1

# .PHONE伪目标,具体含义百度一下一大堆介绍
.PHONY:all clean

# 要生成的目标文件
all: $(TARGET)

# 第一行依赖关系:冒号后面为依赖的文件,相当于Hello: main.o a.o b.o
# 第二行规则:$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
$(TARGET): $(OBJS)
	$(LD) -o $@ $^

# 上一句目标文件依赖一大堆.o文件,这句表示所有.o都由相应名字的.c文件自动生成
%.o:%.c
	$(CC) -c $^ 

# make clean删除所有.o和目标文件
clean:
	rm -f $(OBJS) $(TARGET)

总结如下:
1)实现不够通用,只能对特定观察者才能有效(只能对observer抽象类的派生类才能生效,且不能带参数)
2)需要继承,强对象关系,不够灵活
3)观察者被通知的接口参数不支持变化,导致观察者不能应付接口的变化

2)改进的观察者模式
1)通过该被通知接口参数化和std::function代替继承
2)通过可变参数模板和完美转发消除接口变化的影响
3)方便增加或者移除观察者
4)将类设置不可复制

class NonCopyable
{
protected:
    NonCopyable() = default;
    ~NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete; //禁止复制构造
    NonCopyable & operator = (const NonCopyable&) = delete; //禁止赋值构造
};

#include <iostream>
#include <string>
#include <functional>
#include <map>
using namespace std;

template<typename Func>
class Events : NonCopyable
{
public:
    Events(){}
    ~Events(){}

    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;  //观察者列表
};

struct stA
{
    int a, b;
    void print(int a, int b){
        cout <<"stA:" << a <<","<<b << endl;
    }
};

void print(int a, int b){
    cout << a <<","<<b << endl;
}

int main(){
    Events<std::function<void(int, int)>> myevent;
    
    auto key = myevent.Connect(print); //以函数方式注册观察者

    stA t;
    auto lambdakey = myevent.Connect([&t](int a, int b){t.a = a; t.b = b;});//lambda注册

    std::function<void(int, int)> f = std::bind(&stA::print, &t, std::placeholders::_1, std::placeholders::_2);// std::function注册
    myevent.Connect(f);

    int a=1,b=2;
    myevent.Notify(a, b);  //广播所有观察者

    myevent.Disconnect(key); //移除观察者

    return 0;
}

总结:
类内部维护了一个泛型函数列表,观察者只需要将观察者函数注册进来即可,消除了继承引起的强耦合;通过接口使用了可变参数模块,支持任意参数,消除了接口变化

3、访问者模式

#include <iostream>
using namespace std;

//没使用访问者模式
namespace unVisit {

    //foo1和foo2是原有接口,但是现在要新增foo3。
    class Composite {
    public:
        virtual void foo1() = 0;
        virtual void foo2() = 0;
        virtual void foo3() = 0;    //新增代码
    };

    class Composite1 : public Composite {
    public:
        void foo1() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        void foo2() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        //新增代码
        void foo3() override {
            cout << "新增函数" << endl;
        }
    };

    class Composite2 : public Composite {
    public:
        void foo1() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        void foo2() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        //新增代码
        void foo3() override {
            cout << "新增函数" << endl;
        }
    };
}

namespace Visit {

    class Composite;
    class Composite1;
    class Composite2;

    //非仿函数版本
    class Visit {
    public:
        virtual void composite1(Composite &composite) = 0;
        virtual void composite2(Composite &composite) = 0;
    };

    //仿函数
    class Foo {
    public:
        virtual void operator()(Composite1 &composite1) = 0;
        virtual void operator()(Composite2 &composite1) = 0;
    };

    class Composite {
    public:
        virtual void foo1() = 0;
        virtual void foo2() = 0;

        //预留接口(非仿函数版本)
        virtual void futureFoo(Visit &visit) = 0;
        //仿函数版本
        virtual void operatorFoo(Foo &foo) = 0;
    };

    class Composite1 : public Composite {
    public:
        void foo1() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        void foo2() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        void futureFoo(Visit &visit) override {
            visit.composite1(*this);
        }

        void operatorFoo(Foo &foo) override {
            foo.operator()(*this);
        }
    };

    class Composite2 : public Composite {
    public:
        void foo1() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        void foo2() override {
            cout << __PRETTY_FUNCTION__ << endl;
        }

        void futureFoo(Visit &visit) override {
            visit.composite2(*this);
        }

        void operatorFoo(Foo &foo) override {
            foo.operator()(*this);
        }
    };

    //以后新增接口直接创建Visit子类就行
    class Visit1 : public Visit {
    public:
        void composite1(Composite &composite) override {
            cout << "新增函数" << endl;
        }

        void composite2(Composite &composite) override {
            cout << "新增函数" << endl;
        }
    };

    //以后新增接口直接创建Foo子类就行
    class Foo1 : public Foo {
    public:
        void operator()(Composite1 &composite1) override {
            cout << "新增函数" << endl;
        }

        void operator()(Composite2 &composite1) override {
            cout << "新增函数" << endl;
        }
    };
    
// private:
//     //foo是可以有参数的。
}

int main()
{
    unVisit::Composite1().foo3();
    unVisit::Composite2().foo3();

    Visit::Visit1 foo3;
    Visit::Composite1().futureFoo(foo3);
    Visit::Composite2().futureFoo(foo3);

    Visit::Foo1 _foo3;
    Visit::Composite1().operatorFoo(_foo3);
    Visit::Composite2().operatorFoo(_foo3);

    return 0;
}

访问者模式

#include <iostream>
#include <memory>

using namespace std;

struct  ConcreteElement1;
struct  ConcreteElement2;
//访问者基类
struct Visitor{
    virtual ~Visitor(){}
    virtual void Visit(ConcreteElement1* element) = 0;
    virtual void Visit(ConcreteElement2* element) = 0;
};

//被访问者基类
struct Element{
    virtual ~Element(){}
    virtual void Accept(Visitor& visitor) = 0;
};

//具体的访问者
struct  ConcreteVisitor : public Visitor{
    void Visit(ConcreteElement1 *element){
        cout << "Visit ConcreteElement1" << endl;
    }

    void Visit(ConcreteElement2 *element){
        cout << "Visit ConcreteElement2" << endl;
    }
};

//具体的被访问者
struct  ConcreteElement1 : public Element{
    void Accept(Visitor& visitor){
        visitor.Visit(this); //二次分派
    }
};

//具体的被访问者
struct  ConcreteElement2 : public Element{
    void Accept(Visitor& visitor){
        visitor.Visit(this);//二次分派
    }
};

int main()
{
    ConcreteVisitor v;
    std::unique_ptr<Element> emt1(new ConcreteElement1());
    std::unique_ptr<Element> emt2(new ConcreteElement2());

    emt1->Accept(v);
    emt2->Accept(v);
}

总结:
定义对象的结构类很少改变,但需要在结构之上定义新的结构
改变对象结构类需要重新定义对所有访问者的接口,改动太大

#include <iostream>

template<typename... Types>
struct  Visitor;

template<typename T, typename... Types>
struct Visitor<T, Types...> : Visitor<Types...>
{
    using Visitor<Types...>::Visit;//避免隐藏基类的同名方法
    virtual void Visit(const T&) = 0; 
};

template<typename T>
struct Visitor<T>
{
    virtual void Visit(const T&) = 0; 
};

struct  stA;
struct  stB;

struct Base
{
    //定义通用的访问类型,它可以访问stA和stB
    typedef Visitor<stA, stB> MytVisitor; //会自动生成stA和stB的visit虚函数,等同于如下
    /*
    	struct Visitor<stA, stB>
		{
			virtual void Visit(const stA&) = 0; 
		    virtual void Visit(const stB&) = 0; 
		};
    */
	//增加新的访问者时,就如下
	//typedef Visitor<stA, stB, stC, stD, stE> MytVisitor;   //同样会自动生成对应的visit虚函数,类似stA和stB的过程
    virtual void Accpet(MytVisitor&) = 0;
};

struct  stA: Base
{
    double val;
    void Accpet(Base::MytVisitor& v){
        v.Visit(*this);
    }
};

struct  stB: Base
{
    int val;
    void Accpet(Base::MytVisitor& v){
        v.Visit(*this);
    }
};

struct PrintVisitor: Base::MytVisitor
{
    void Visit(const stA& a){
        std::cout << "from stA" <<a.val<<std::endl;
    }
    void Visit(const stB& b){
        std::cout << "from stB" <<b.val<<std::endl;
    }    
};

int main()
{
    PrintVisitor vis;
    stA a;
    a.val = 8.97;
    stB b;
    b.val = 8;
    Base *base = &a;
    base->Accpet(vis);
    base = &b;
    base->Accpet(vis);
}

总结:
通过上述方式自动新增被访问者的虚函数, 实现visitor接口层不需要修改保持稳定
把需要visitor接口层变化转移到被访问者基类中,尽管增加新的访问者,基类中visitror类型需要扩展,但相对修改会比较小

4、改进命令模式

命令模式可用来消除程序中的耦合问题,例如以下

#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <cstdlib>

using namespace std;

class Task
{
public:
    virtual void operation() = 0;
};

//单例
class TaskRunner
{
public:
    static void add(Task& t){
        tasks.push_back(&t);
    }
    static void run(){
        vector<Task*>::iterator it = tasks.begin();
        while (it != tasks.end()) {
            (*it++)->operation();
        }
    }

private:
    static vector<Task*> tasks;
    TaskRunner(){}
    static TaskRunner tr;
};


TaskRunner TaskRunner::tr;
vector<Task*> TaskRunner::tasks;

//创建随机延迟时间
//clock() 返回从开启程序进程到调用clock()时的时间。
class EventSimulator
{
public:
    EventSimulator():creation(clock()) {
        delay = CLOCKS_PER_SEC/4 * (rand() % 20 + 1);
        cout << "delay = " << delay << endl;
    }

    bool fired(){
        return clock() > creation + delay;
    }

private:
    clock_t creation;
    clock_t delay;
};

class Button{
public:
    Button(string name):pressed(false),id(name){}
    void press(){pressed = true;}
    bool isPressed(){
        if(e.fired()) press();
        return pressed;
    }

    friend ostream& operator <<(ostream & os,const Button& b){
        return os << b.id;
    }

private:
    bool pressed;
    string id;
    EventSimulator e;
};

class CheckButton : public Task
{
public:
    CheckButton(Button & b):button(b),handled(false) {}
    void operation(){
        if(button.isPressed() && !handled){
            cout << button << " pressed" << endl;
            handled = true;
        }
    }

private:
    Button & button;
    bool handled;
};

void procedure1(){
    TaskRunner::run(); // check all events
}
void procedure2(){
    TaskRunner::run(); // check all events
}
void procedure3(){
    TaskRunner::run(); // check all events
}

int main()
{
    srand(time(0));
    Button b1("Button 1"),b2("Button 2"),b3("Button 3");
    CheckButton cb1(b1),cb2(b2),cb3(b3);
    TaskRunner::add(cb1);
    TaskRunner::add(cb2);
    TaskRunner::add(cb3);
    cout<< "Control-C to exit" << endl;

    while (true) {
        procedure1();
        procedure2();
        procedure3();
    }
    return 0;
}
/*
命令对象由被单例 TaskRunner执行的 Task 表示。EventSimulator创建一个随机延迟时间,所以当周期性的调用函数fired()时,在某个随机时间段,其返回结果从 true 和 false 变化。EventSimulator对象类 Button 中使用,模拟在某个不可预知的时间段用户时间发生的动作。CheckButton 是Task 的实现,在程序中通过所有“正常”代码对其进行周期性检查,就是这里的procedure1(),procedure2(),procedure3()的末尾
*/

总结:当请求越多,所需要的命令类也越多,导致类的爆炸

泛型简单命令类的实现

class Commond
{
public:
    Commond();
    ~Commond();
    virtual void Execute() = 0;
};

template<class Receiver>
class SimpleCommand : public Commond {
public:
    typedef void (Receiver::*Action)();
    SimpleCommand(Receiver *r, Action a):_receiver(r),_action(a){}
    virtual void Execute();
private:
    Action _action;
    Receiver* _receiver;
};

template<class Receiver>
void SimpleCommand<Receiver>::Execute(){
    (_receiver->*_action)();
}

class MyClass
{
public:
    void Action();
};

int main()
{
    MyClass* receiver = new MyClass;
    Commond* aCommond = new SimpleCommand<MyClass>(receiver, &MyClass::Action);
    aCommond->Execute();

    return 0;
}

避免了不断创建新的命令类,但不能对所有的复杂的命令类泛化

解决问题的思路:
1)如何通用的泛化的所有命令类,让命令类接受所有的成员函数指针或者函数对象

#include <functional>
#include <type_traits>
#include <iostream>
 
using namespace std;
 
namespace CppHelper
{
 
template<typename Ret=void>
struct CCommand
{
private:
    std::function < Ret()> m_func;
 
public:
    //接受function、函数对象、lamda和普通函数的包装器
    template< class Func, class... Args, class = typename std::enable_if<!std::is_member_function_pointer<Func>::value>::type>
    void Wrap(Func && func, Args && ... args)
    {
        m_func = [&]{return func(args...); };
    }
    //接受常量成员函数的包装器
    template<class CObj, class... DArgs, class PObj, class... Args>
    void Wrap(Ret(CObj::*func)(DArgs...) const, PObj && pObj, Args && ... args)
    {
        m_func = [&, func]{return (*pObj.*func)( args...); };
    }
 
    //接受非常量成员函数的包装器
    template<class CObj, class... DArgs, class PObj, class... Args>
    void Wrap(Ret(CObj::*func)(DArgs...), PObj && pObj, Args && ... args)
    {
        m_func = [&, func]{return (*pObj.*func)( args...); };
    }
 
    Ret Excecute()
    {
        return m_func();
    }
};
}

struct STA
{
    int m_a;
    int operator()(){ return m_a; }
    int operator()(int n){ return m_a + n; }
    int triple0(){ return m_a * 3; }
    int triple(int a){ return m_a * 3 + a; }
    int triple1() const { return m_a * 3; }
    const int triple2(int a) const { return m_a * 3+a; }
    void triple3(){ cout << "" <<endl; }
};
 
int add_one(int n)
{
    return n + 1;
}

int main()
{
    CppHelper::CCommand<int> cmd;
    //普通函数
    cmd.Wrap(add_one, 0);
    cout << cmd.Excecute()<< endl;
 
    //lambda表达式
    cmd.Wrap([](int n){return n + 1; }, 1);
    cout << cmd.Excecute()<< endl;
 
    //函数对象
    cmd.Wrap(STA());
    cout << cmd.Excecute()<< endl;
    cmd.Wrap(STA(), 4);
    cout << cmd.Excecute()<< endl;
 
    STA t = { 10 };
    int x = 3;
    //成员函数
    cmd.Wrap(&STA::triple0, &t);
    cout << cmd.Excecute()<< endl;
    cmd.Wrap(&STA::triple, &t, x);
    cout << cmd.Excecute()<< endl;
    cmd.Wrap(&STA::triple, &t, 3);
    cout << cmd.Excecute()<< endl;
 
    //常量成员
    CppHelper::CCommand<const int> cmd1;
    cmd1.Wrap(&STA::triple2, &t, 3);
    cout << cmd1.Excecute()<< endl;
 
    CppHelper::CCommand<> cmd2;
    cmd2.Wrap(&STA::triple3, &t);
    cmd2.Excecute();
}

5、改进对象池模式

避免重复创建开销比较大的对象,通过对象池来优化
思路如下:
先创建好一批对象,放到集合中,每当程序需要新对象时,从对象池获取,用完归还对象池即可。避免重复创建对象,提高程序性能

#include <functional>
#include <iostream>
#include <map>
#include <memory>

using namespace std;
const int MaxObjectNum = 10;

template<typename T>
class ObjectPoll
{
    template<typename... Args>
    using Constructor = std::function<std::shared_ptr<T>(Args...)>;
public:
    ObjectPoll():needClear(false){}
    ~ObjectPoll(){
        needClear = true;
    }

    //默认创建多少个对象
    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 construcrName = typeid(Constructor<Args...>).name();//不区分引用
        for(size_t i = 0; i < num; i++){
            m_object_map.emplace(construcrName, shared_ptr<T>(new T(std::forward<Args>(args)...), [this, construcrName](T* p){
                return createPtr<T>(string(construcrName), args...);
            }));
        }
    }

    template<typename T, typename... Args>
    std::shared_ptr<T> createPtr(std::string& construcrName, Args... args){
        return std::shared_ptr<T>(new T(args...), [construcrName, this](T* t){
            if(needClear)
                delete[] t;
            else
                m_object_map.emplace(construcrName, std::shared_ptr<T>(t));
        });
    }

    //从对象池获取一个对象
    template<typename... Args>
    std::shared_ptr<T> Get(){
        string construcrName = typeid(Constructor<Args...>).name();
        auto range = m_object_map.equal_range(construcrName); //二分查找
        for(auto it = range.first; it != range.second; ++it){
            auto ptr = it->second;
            m_object_map.erase(it);
            return ptr;
        }

        return nullptr;
    }

private:
    std::multimap<std::string, std::shared_ptr<T>> m_object_map;
    bool needClear;
};

总结:
1)对象用完需要手动回收,存在忘记回收的风险
2)不支持参数不同的构造函数
上述问题两个问题在C++11中可如下解决:
1)使用智能指针实现自动回收
2)通过可变参数模板来解决

// ObjectPool.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <map>
 
using namespace std;
const int MaxObjectNum = 10;
 
class NonCopyable
{
protected:
	NonCopyable() = default;
	~NonCopyable() = default;
	// 禁用复制构造
	NonCopyable(const NonCopyable&) = delete;
	// 禁用赋值构造
	NonCopyable& operator = (const NonCopyable&) = delete;
};
 
template<typename T>
class ObjectPool :NonCopyable
{
	template<typename...Args>
	using Constructor = function<shared_ptr<T>(Args...)>;
public:
	// 默认创建多少个对象
	template<typename... Args>
	void Init(size_t num, Args&&...args)
	{
		if (num <=0 || num>MaxObjectNum)
		{
			throw 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(forward<Args>(args)...), [this, constructName](T*p) {
				//删除器中不直接删除对象,而是回收到对象池中,以供下次使用
				m_object_map.emplace(move(constructName), shared_ptr<T>(p));
			}));
 
		}
	}
	// 从对象池中获取一个对象
	template<typename... Args>
	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,shared_ptr<T>> m_object_map;
};
 
struct BigObject
{
	BigObject() {}
	BigObject(int a) {}
 
	BigObject(const int& a, const int&b) {}
	void Print(const string& str)
	{
		cout << str << endl;
	}
};
 
void Print(shared_ptr<BigObject>p, const string& str)
{
	if (p != nullptr)
	{
		p->Print(str);
	}
}
 
void TestObjPool()
{
	ObjectPool<BigObject> pool;
	pool.Init(2);
	{
		auto p = pool.Get();
		Print(p, "p");
		auto p2 = pool.Get();
		Print(p2, "p2");
		// 出了作用哉之后,对象池返回出来的对象又会自动回收
	}
	auto p = pool.Get();
	Print(p, "p");
	auto p2 = pool.Get();
	Print(p2, "p2");
 
	// 对象池支持重载构造函数
	pool.Init(2, 1);
	auto p4 = pool.Get<int>();
	Print(p4, "p4");
	pool.Init(2, 1, 2);
	auto p5 = pool.Get<int, int>();
	Print(p5, "p5");
}
int main()
{
	TestObjPool();
}

总结:
1)对象被回收之后,它的状态没有被清楚,从对象池模式去除来时最好重置一下状态
2)构造对象时,构造函数入参的引用将被忽略,即int和ini&会被认为时同一种构造函数,原因为构造对象的时候无法获取变参Args…的引用类型,丢失了引用相关信息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值