模板方法模式混乱

时间:2013-12-31 02:46:33

标签: c++ hook template-method-pattern

这里钩子函数本身需要检查同样属于类层次结构的数据成员的typeid。所以我为这个类层次结构定义了一个模板方法。这是我遇到的混乱:

void Person::leave() {
    // code
    hook();  // private virtual 
    // code
}

void Girl::hook() {  // Girl is a derived class of Person, with data member location 
                 // of type Location which itself has a derived class House
    // code
    location.locationHook(this);// what happens here depends on what kind of location she is in
    // code
}

void Location::locationHook(Person* person) {
    // Oh oh!  This depends on what class person is
}

void House::locationHook(Person* person) {
    // Oh oh!  This depends on what class person is

}

因此,对于这种情况,我不得不求助于我的原始方法,对每种类型的Person派生类使用typeid(* person)和dynamic_cast以及if语句来定义虚拟locationHook,对吗?

2 个答案:

答案 0 :(得分:0)

这是我提出的解决方案。我测试它是否有效,但我不知道它是否得到任何批准(或者它是否会一直有效):

void Person::leave() {
    // code
    hook();
}

void Person::hook() {
    // code
    location.locationHook (this);
}

void Girl::hook() {
    // code 
    location.locationHook (this);
}

void Location::locationHook (Person* person) {
    // code
    person->removeFromLocation();
}

void House::locationHook (Person* person) {
    // code 
    person->removeFromHouse();
}

// removeFromLocation() and removeFromHouse() are also virtual functions of Person

答案 1 :(得分:0)

这是使用双重调度的替代解决方案:

#include <iostream>
#include <list>

struct Person;  struct Girl;  struct Guy;

struct Location {
    virtual void hook (Person*) = 0;
    virtual void hook (Girl*) = 0;
    virtual void hook (Guy*) = 0;
};

struct House : Location {
    virtual void hook (Person*) override;
    virtual void hook (Girl*) override {
        std::cout << "Girl left the house.\n";
    }
    virtual void hook (Guy*) override {
        std::cout << "Guy left the house.\n";
    }
};

struct Person {
    Location* location = new House;
    void leave() {
        // ...
        hook();
        // ...
    }
    virtual void invoke_hook (Location*) = 0;
private:
    virtual void hook() = 0;
};

struct Girl : Person {
    virtual void hook() override { 
        std::cout << "Girl will leave the house.\n";
        location->hook(this);
        // ...
    }
    virtual void invoke_hook (Location* location) override { location->hook(this); }  // Double dispatch
};

struct Guy : Person {
    virtual void hook() override { 
        std::cout << "Guy will leave the house.\n";
        location->hook(this);
        // ...
    }
    virtual void invoke_hook (Location* location) override { location->hook(this); }  // Double dispatch
};

void House::hook (Person* person) {
    person->invoke_hook(this);  // Double dispatch
}

int main() {
    std::list<Person*> people = {new Girl, new Guy};
    for (Person* p : people)
        p->leave();  // Simple overloads will do the job here.

    House* house = new House;
    for (Person* p : people)
        house->hook(p);  // Double dispatch used.
}

输出:

Girl will leave the house.
Girl left the house.
Guy will leave the house.
Guy left the house.
Girl left the house.
Guy left the house.