2

私のプロジェクトには、さまざまな形式からロードおよび再ロードできる Resource オブジェクトがあります。ロード アルゴリズムは、さまざまな ResourceLoader サブクラスで実装されます。

class Resource
{
private:

    // Not for client access    
    Type1 InternalData1;
    Type2 InternalData2;
    TypeN InternalDataN;

    ResourceLoader Loader;

public:

    // Any client interface
    void UseResource();
};

class ResourceLoader
{
public:

    void Load(Resource& R) = 0;
};

class ResourceLoaderFormat1: public ResourceLoader
{
public:

    void Load(Resource& R) { ...loads Resource from Format1... }
};    

class ResourceLoaderFormat2: public ResourceLoader
{
public:

    void Load(Resource& R) { ...loads Resource from Format2... }
};

ローダーは指定された形式で入力を読み取り、ターゲットの Resource オブジェクト R を初期化します。ローダーはリソース内に格納されるため、リソースが無効になると、格納されたローダーを使用して自身をリロードします。

問題は、ローダーがリソースを初期化する方法です。

  1. すべての InternalData フィールドをパブリックにします。それらへのクライアントアクセスを許可しますが、これは良くありません。
  2. Loader を Resource のフレンドにします。特定の形式の新しいローダーはそれぞれリソース ヘッダーに追加されるため、拡張性が失われ、拡張機能を作成するプログラマは基本コードに触れる必要があります。
  3. InternalData ごとにセッターを提供します。すべてのクライアントがデータを変更する可能性があるため、変更してはならないため、それらをすべて公開することはそれほど遠くありません。
  4. Resource::Setup(InternalData1, InternalData2, InternalDataN) を提供するか、それらすべてを何らかの構造体でラップして、その構造体を渡します。すべてのフィールドが一度に設定されることを除いて、3. と同じです。

問題は、 Resource クラスのフィールドは、拡張可能な一連のクラスからの書き込みにはアクセスできなければならず、クライアント コードからの書き込みにはアクセスできない必要があることです。良いOOPソリューションはありますか? ありがとう。

4

2 に答える 2

1

別の解決策は(私の最初のコメントで説明したように):

class ResourceClient
{
    public:
        virtual void UseResource() = 0;
}
class ResourceLoader
{
    public:
         virtual void SetResource() = 0;
}
class Resource:
    public ResourceClient,
    public ResourceLoader
{
private:

    // Not for client access    
    Type1 InternalData1;
    Type2 InternalData2;
    TypeN InternalDataN;

    ResourceLoader Loader;

public:

    // Any client interface
    virtual void UseResource();
    virtual void SetResource();
};

class ResourceLoader
{
public:

    void Load(ResourceLoader& R) = 0;
};

class ResourceLoaderFormat1: public ResourceLoader
{
public:

    void Load(ResourceLoader& R) { ...loads Resource from Format1... }
};    

class ResourceLoaderFormat2: public ResourceLoader
{
public:

    void Load(ResourceLoader& R) { ...loads Resource from Format2... }
};

Resource を記述する必要がある関数のセットは ResourceLoader ポインターを使用し、修正された関数は ResourceClient ポインターを使用してリソースにアクセスします。

このソリューションの利点は、書き込みアクセスを使用するクラスまたは関数をフレンドとして宣言する必要がないことです。あなたがやりたいこと、またはやりたい機能に応じて正しいインターフェースを使用するだけです

于 2016-02-18T11:04:45.183 に答える