如何实现与继承一起的Observer模式?

如何实现与继承一起的Observer模式?

问题描述:

我有一个管理配置文件SettingsController的类,它允许注册一个SettingsClient(一个纯虚函数,没有成员)。当相关配置条目发生更改时,将会通知SettingsClient,以便刷新。如何实现与继承一起的Observer模式?

现在我有一个RepositoryBase其需要一些配置条目并因此继承SettingsClient并在SettingsController和混凝土库ConcreteRepository这也需要一些配置条目并且继承客户端和寄存器在控制器注册。

ConcreteRepository继承RepositoryBase无一不继承SettingsClient能够在控制器注册(在Java中ConcreteRepositoryextendRepositoryBase两者将implementSettingsClient)。

我的问题是:编译器警告我不要这样做,因为它是模棱两可的。可悲的虚拟继承在这里不会帮助我,因为它会覆盖ConcreteRepositoryRepositoryBase的已实现函数,因此禁用两个类之一的刷新功能。

有没有办法实现这种继承 - 观察者组合?我想这可能是一个设计上的缺陷和RepositoryBase需要成为ConcreteRepository成员

下面是一些代码来给出一个概述(?):

#include <vector> 
#include <iostream> 

class SettingsClient { 
public: 
    virtual void reloadSettings() = 0; 
}; 

class SettingsController { 
    void notify(){ 
    for(SettingsClient* client : clients){ 
     client->reloadSettings(); // error! reloadSettings() of RepositoryBase or ConcreteRepository? 
    } 
    } 
    void registerClient(SettingsClient *client) { 
    clients.push_back(client); 
    } 

    std::vector<SettingsClient*> clients; 
}; 

class RepositoryBase : private SettingsClient { 
    // ... 
    virtual void reloadSettings() { 
    std::cout << "Reloading Base!" << "\n"; 
    } 
    // ... 
}; 

class ConcreteRepository : private SettingsClient, private RepositoryBase { 
    // ... 
    virtual void reloadSettings() { 
    std::cout << "Reloading ConcreteRepository!" << "\n"; 
    } 
    // ... 
}; 
+0

公共继承因此多态性与工作,SettingsClient需要一个虚拟析构函数,ConcreteRepository不需要也继承SettingsClient,因为它已经是一个通过RepositoryBase,并显式调用RepositoryBase的ReloadSettings从ConcreteBase的,如果你需要。 C++中没有默认调用多个基类重写成员的机制。 – evan

没有必要ConcreteRepository也继承从SettingsClient。您可以在基类构造函数中注册一次仓库,然后从子类版本调用基类reloadSettings

class RepositoryBase : private SettingsClient 
{ 
public: 
    RepositoryBase(SettingsController& controller) 
    { 
    controller.registerClient(this); 
    } 

private: 
    void reloadSettings() override 
    { 
    std::cout << "Reloading RepositoryBase\n"; 
    } 
}; 

class ConcreteRepository : public RepositoryBase 
{ 
public: 
    using RepositoryBase::RepositoryBase; 

private: 
    void reloadSettings() override 
    { 
    std::cout << "Reloading ConcreteRepository\n"; 
    } 
}; 

我们使用私人继承从SettingsClient防止reloadSettings被在子类中公开可见。如果我们需要调用基类函数,我们可以使用保护继承来代替,这是以弱化封装为代价的。

class RepositoryBase : protected SettingsClient 
{ 
public: 
    RepositoryBase(SettingsController& controller) 
    { 
    controller.registerClient(this); 
    } 

protected: 
    void reloadSettings() override 
    { 
    std::cout << "Reloading RepositoryBase\n"; 
    } 
}; 

class ConcreteRepository : public RepositoryBase 
{ 
public: 
    using RepositoryBase::RepositoryBase; 

protected: 
    void reloadSettings() override 
    { 
    RepositoryBase::reloadSettings(); 
    std::cout << "Reloading ConcreteRepository\n"; 
    } 
}; 

如果您需要或更喜欢为基类和子类注册两个单独的客户端,则可以使用组合。

class RepositoryBase 
{ 
public: 
    RepositoryBase(SettingsController& controller) 
    { 
    controller.registerClient(&client); 
    } 

private: 
    struct : public SettingsClient 
    { 
    void reloadSettings() override 
    { 
     std::cout << "Reloading RepositoryBase\n"; 
    } 
    } client; 
}; 

class ConcreteRepository : public RepositoryBase 
{ 
public: 
    ConcreteRepository(SettingsController& controller) : RepositoryBase(controller) 
    { 
    controller.registerClient(&client); 
    } 

private: 
    struct : public SettingsClient 
    { 
    void reloadSettings() override 
    { 
     std::cout << "Reloading ConcreteRepository\n"; 
    } 
    } client; 
}; 

如果您需要访问其非静态成员,则可以为客户端指定一个指向其存储库的指针。