C++ 之 委托模式

原文地址

成员函数指针

class A{                       
public:
 
    void Func(int){            
        std::cout << "I am in A" << std::endl;
    }                          
};
void (A::*pFunc)(int) = &A::Func;

使用模板类

template <typename T>
class DelegateHandler{
public:
    DelegateHandler(T *pT, void (T::*pFunc)(int)) : m_pT(pT),
                m_pFunc(pFunc){}
 
    void Invoke(int value){
        (m_pT->*m_pFunc)(value);
    }
 
private:
    T *m_pT;
    void (T::*m_pFunc)(int);
};
A a;
DelegateHandler<A> dha(&a, &A::Func);
dha.Invoke(3);
 
B b;
DelegateHandler<B> dhb(&b, &B::Method);   //B::Method的声明与A::Func类似
dhb.Invoke(4);

到这里产生了一个问题:如果希望调用的目标是非成员函数,怎么办?上面的类模板无法调用非成员函数,不过使用模板偏特化就可以解决这个问题:

template<>
class DelegateHandler<void>{  //void代替前面的类型T,表示类模板没有参数
 
public:
    DelegateHandler(void(*pFunc)(int)) : m_pFunc(pFunc){}
 
    void Invoke(int value){
        (*m_pFunc)(value);
    }
 
private:
    void(*m_pFunc)(int);
};

非成员函数的使用方法:

void NonmemberFunc(int param){
    std::cout << "I am in NonmemberFunc!" << std::endl;
}
 
DelegateHandler<void> dhf(NonmemberFunc);
dhf.Invoke(5);

使用多态

对于单目标的委托来说,使用上面的代码或许就已经足够了。但是我的目的当然不止于此,我想要的是多目标的委托。多目标委托其实就是一个容器,在这个容器里可以存放多个对象(这里的对象指的是委托对象,不是A也不是B),当调用委托的时候依次调用每个对象。容器里的对象应该都是相同的类型,这样才能够放到强类型的容器中;而且委托调用方不应该知道具体的调用目标是什么,所以这些对象也应该要隐藏具体的细节。遗憾的是,上一步中实现的类模板都不具备这些能力,DelegateHandler和DelegateHandler是不同的类型,不能放到同一个容器中,调用方要调用它们也必须知道调用的目标是什么类型。

解决这个问题的方法就是使用多态,令所有的委托目标类都继承一个公共的接口,调用方只通过这个接口来进行调用,这样就不必知道每个目标(这里的目标还是指的委托)具体的类型。下面就是该接口的定义

class IDelegateHandler{
public:
    virtual ~IDelegateHandler(){}
    virtual void Invoke(int) = 0;
};

然后令DelegateHandler继承该接口:

template<typename T>
class DelegateHandler : public IDelegateHandler{
public:
    DelegateHandler(T *pT, void (T::*pFunc)(int)) : m_pT(pT),
        m_pFunc(pFunc){}
 
    virtual void Invoke(int value) override {
        (m_pT->*m_pFunc)(value);
    }
 
private:
    T *m_pT;
    void (T::*m_pFunc)(int);
 
};
 
template<>
class DelegateHandler<void> : public IDelegateHandler{
public:
    DelegateHandler(void (*pFunc)(int)) : m_pFunc(pFunc){}
    virtual void Invoke(int value) override{
        (*m_pFunc)(value);
    }
private:
    void (*m_pFunc)(int);
 
};

现在可以将各种类型的DelegateHandler放到同一个容器中,并使用同样的方式来调用了:

A a;
B b;
DelegateHandler<A> dha(&a, &A::*Func);
DelegateHandler<B> dhb(&b, &B::*Method);
DelegateHandler<void> dhf(NonmemberFunc);
 
std::vector<IDelegateHandler*> handlers;
handlers.push_back(&dha);
handlers.push_back(&dhb);
handlers.push_back(&dhf);
 
//这里的auto等于std::vector<IDelegateHandler*>::const_iterator
for (auto itor = handlers.cbegin(); itor != handlers.cend(); ++itor){
    (*itor)->Invoke(7);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
建造者模式是一种创建型设计模式,它允许您创建不同类型的对象,而无需暴露对象的创建逻辑。它将对象的构建步骤分解为可重用的部分,并允许您按顺序执行它们。这使得您能够创建具有不同属性的对象,而无需编写大量的重复代码。 在建造者模式中,有一个建造者类,它负责创建对象的特定部分,如电脑的CPU、内存和硬盘等。该类具有一个公共接口,该接口定义了每个部分的构建步骤。在构建步骤完成后,该类可以返回一个完整的对象。 建造者模式也包括一个指导者类,它负责调用建造者类的构建步骤,并按照正确的顺序执行它们。指导者类知道如何创建对象,但不知道如何创建对象的每个部分,因此它将这个工作委托给建造者类。 以下是一个简单的C++实现建造者模式的示例代码: ```cpp #include <iostream> #include <string> class Computer { public: void setCPU(const std::string& cpu) { m_cpu = cpu; } void setMemory(const std::string& memory) { m_memory = memory; } void setHardDisk(const std::string& hardDisk) { m_hardDisk = hardDisk; } void show() { std::cout << "CPU: " << m_cpu << std::endl; std::cout << "Memory: " << m_memory << std::endl; std::cout << "Hard Disk: " << m_hardDisk << std::endl; } private: std::string m_cpu; std::string m_memory; std::string m_hardDisk; }; class Builder { public: virtual ~Builder() {} virtual void buildCPU() = 0; virtual void buildMemory() = 0; virtual void buildHardDisk() = 0; virtual Computer* getResult() = 0; }; class Director { public: void setBuilder(Builder* builder) { m_builder = builder; } void construct() { m_builder->buildCPU(); m_builder->buildMemory(); m_builder->buildHardDisk(); } private: Builder* m_builder; }; class DesktopBuilder : public Builder { public: DesktopBuilder() { m_computer = new Computer; } ~DesktopBuilder() { delete m_computer; } void buildCPU() { m_computer->setCPU("Intel Core i7"); } void buildMemory() { m_computer->setMemory("16GB DDR4 RAM"); } void buildHardDisk() { m_computer->setHardDisk("2TB SATA Hard Disk"); } Computer* getResult() { return m_computer; } private: Computer* m_computer; }; int main() { Director director; DesktopBuilder desktopBuilder; director.setBuilder(&desktopBuilder); director.construct(); Computer* computer = desktopBuilder.getResult(); computer->show(); return 0; } ``` 在这个示例中,我们创建了一个Computer类,它有三个成员变量:CPU、内存和硬盘。我们还创建了一个Builder类,它定义了创建Computer对象的构建步骤,并且为每个部分提供了一个抽象接口。我们还创建了一个Director类,它负责调用建造者类的构建步骤,并按照正确的顺序执行它们。 在具体的建造者实现中,我们创建了一个DesktopBuilder类,它实现了Builder接口,并具有一个Computer成员变量。在DesktopBuilder类的构建步骤中,我们设置了Computer对象的CPU、内存和硬盘。最后,我们返回一个完整的Computer对象。 在main函数中,我们创建了一个Director对象,并将DesktopBuilder对象传递给setBuilder函数。然后我们调用construct函数,它将调用DesktopBuilder的构建步骤,并返回一个完整的Computer对象。我们最后打印出这个对象的属性,以验证它是否被正确构建。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值