2

在我的项目中,我有可以从不同格式加载和重新加载的资源对象。加载算法在不同的 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... }
};

Loader 以给定格式读取输入并初始化其目标 Resource 对象 R。Loader 存储在资源中,因此如果资源变得无效,它会使用存储的 loader 重新加载自身。

问题是加载器应该如何初始化资源?

  1. 公开所有 InternalData 字段。它授予客户对它们的访问权限,这是不好的。
  2. 让 Loader 成为 Resource 的朋友。每个特定格式的新加载器都将被添加到资源头中,从而扼杀可扩展性,并要求任何编写扩展的程序员接触基本代码。
  3. 为每个 InternalData 提供 setter。离公开它们不远了,因为任何客户端都可以更改它不能更改的数据。
  4. 提供 Resource::Setup(InternalData1, InternalData2, InternalDataN),或者将它们全部包装在某个结构中并传递该结构。与 3 相同。除了一次设置所有字段。

问题是资源类字段必须可以从可扩展的类集写入访问,并且必须不可访问以从客户端代码写入。有什么好的OOP解决方案吗?谢谢。

4

2 回答 2

1

假设我们选择

让 Loader 成为 Resource 的朋友。

有缺点

每个特定格式的新加载器都将被添加到资源头中,从而扼杀可扩展性,并要求任何编写扩展的程序员接触基本代码。


但是,由于您将加载器拆分为基类 + 派生类,因此您只需授予对 的访问权限Loader,并Loader通过protected成员授予子类访问权限。

class Resource
{
    Type1 InternalData1;
    ...
    friend class ResourceLoader;
};

class ResourceLoader
{
    ...
protected:
    static void setResourceInternalData1(Resource &r, const Type1 &val1);
    ...
};

所有ResourceLoader子类现在都可以访问这些设置器,因为它们是protected

class ResourceLoaderFormat1: public ResourceLoader;
class ResourceLoaderFormat2: public ResourceLoader;

只要您不Resource经常更改数据成员,这将很有效。

于 2016-02-18T10:22:59.270 回答
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 指针访问资源。

此解决方案的优点是您不需要使用写访问权限声明任何类或函数为朋友。Juste根据您想要做什么或想要功能能够做什么使用正确的界面

于 2016-02-18T11:04:45.183 回答