構成ファイルを管理するクラスがありSettingsController
、SettingsClient
(1 つの純粋な仮想関数、メンバーなし) を登録できます。SettingsClient
それがリフレッシュすることができるように、関連する設定エントリを変更したときに通知されます。
これで、RepositoryBase
いくつかの構成エントリが必要なため、 で継承SettingsClient
して登録するものSettingsController
と、ConcreteRepository
いくつかの構成エントリが必要で、クライアントを継承してコントローラーで登録する具体的なリポジトリができました。
ConcreteRepository
継承RepositoryBase
との両方継承SettingsClient
コントローラ(Javaの中に登録することができるようにするConcreteRepository
だろうとの両方でしょう)。extend
RepositoryBase
implement
SettingsClient
私の問題は次のとおりです。コンパイラは、あいまいであるため、これを行わないように警告します。悲しいことに、仮想継承はどちらかの実装された機能を上書きし、2 つのクラスのいずれConcreteRepository
かRepositoryBase
の更新機能を無効にするため、ここでは役に立ちません。
この継承とオブザーバーの組み合わせを実現する方法はありますか? これは設計上の欠陥であり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";
}
// ...
};
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";
}
};
基底クラスとサブクラスに 2 つの個別のクライアントを登録する必要がある場合、またはそれを希望する場合は、合成を使用できます。
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;
};
非静的メンバーにアクセスする必要がある場合は、クライアントにリポジトリへのポインタを与えることができます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加