在 C++ 中从另一个初始化 object
Initialize object from another one in C++
在我的项目中,我有资源 objects,可以从不同的格式加载和重新加载。加载算法在不同的ResourceLoader子classes.
中实现
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... }
};
加载程序读取给定格式的输入并初始化其目标资源object R.加载程序存储在资源中,因此如果资源无效,它会使用存储的加载程序重新加载自身。
问题是 Loader 应该如何初始化资源?
- 使所有 InternalData 字段成为 public。它授予客户端访问它们的权限,这并不好。
- 使 Loader 成为 Resource 的朋友。特定格式的每个新加载器都将添加到资源 header,从而破坏可扩展性,并要求任何编写扩展的程序员接触基本代码。
- 为每个 InternalData 提供 setter。离制作所有这些不远了 public,因为任何客户端都可以更改数据,所以它不能更改。
- 提供Resource::Setup(InternalData1、InternalData2、InternalDataN),或将它们全部包装在某种结构中并传递该结构。与3.相同,只是一次设置所有字段。
问题是,资源 class 字段必须可以从可扩展的 class 集合中进行写入,并且必须无法从客户端代码进行写入。有什么好的OOP解决方案吗?谢谢
假设我们选择
Make Loader a friend of Resource.
有缺点
Each new loader for a particular format will be added to a resource header, killing extensibility, and requiring any programmer who writes an extension to touch base code.
但是,由于您将加载程序拆分为基础 class + 派生的 classes,您可以只授予对 Loader
的访问权限,并授予 Loader
subclasses 通过 protected
成员访问。
class Resource
{
Type1 InternalData1;
...
friend class ResourceLoader;
};
class ResourceLoader
{
...
protected:
static void setResourceInternalData1(Resource &r, const Type1 &val1);
...
};
所有 ResourceLoader
subclasses 现在可以访问这些设置器,因为它们是 protected
:
class ResourceLoaderFormat1: public ResourceLoader;
class ResourceLoaderFormat2: public ResourceLoader;
只要您不经常更改 Resource
的数据成员,这就会很好地工作。
另一种解决方案是(如我的第一条评论所述):
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... }
};
需要编写资源的函数集使用 ResourceLoader 指针和受限函数将使用 ResourceClient 指针访问资源。
此解决方案的优点是您不需要声明好友任何 class 或使用写访问权限的函数。只需根据您想做的或想要的功能可以做的,使用正确的界面
在我的项目中,我有资源 objects,可以从不同的格式加载和重新加载。加载算法在不同的ResourceLoader子classes.
中实现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... }
};
加载程序读取给定格式的输入并初始化其目标资源object R.加载程序存储在资源中,因此如果资源无效,它会使用存储的加载程序重新加载自身。
问题是 Loader 应该如何初始化资源?
- 使所有 InternalData 字段成为 public。它授予客户端访问它们的权限,这并不好。
- 使 Loader 成为 Resource 的朋友。特定格式的每个新加载器都将添加到资源 header,从而破坏可扩展性,并要求任何编写扩展的程序员接触基本代码。
- 为每个 InternalData 提供 setter。离制作所有这些不远了 public,因为任何客户端都可以更改数据,所以它不能更改。
- 提供Resource::Setup(InternalData1、InternalData2、InternalDataN),或将它们全部包装在某种结构中并传递该结构。与3.相同,只是一次设置所有字段。
问题是,资源 class 字段必须可以从可扩展的 class 集合中进行写入,并且必须无法从客户端代码进行写入。有什么好的OOP解决方案吗?谢谢
假设我们选择
Make Loader a friend of Resource.
有缺点
Each new loader for a particular format will be added to a resource header, killing extensibility, and requiring any programmer who writes an extension to touch base code.
但是,由于您将加载程序拆分为基础 class + 派生的 classes,您可以只授予对 Loader
的访问权限,并授予 Loader
subclasses 通过 protected
成员访问。
class Resource
{
Type1 InternalData1;
...
friend class ResourceLoader;
};
class ResourceLoader
{
...
protected:
static void setResourceInternalData1(Resource &r, const Type1 &val1);
...
};
所有 ResourceLoader
subclasses 现在可以访问这些设置器,因为它们是 protected
:
class ResourceLoaderFormat1: public ResourceLoader;
class ResourceLoaderFormat2: public ResourceLoader;
只要您不经常更改 Resource
的数据成员,这就会很好地工作。
另一种解决方案是(如我的第一条评论所述):
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... }
};
需要编写资源的函数集使用 ResourceLoader 指针和受限函数将使用 ResourceClient 指针访问资源。
此解决方案的优点是您不需要声明好友任何 class 或使用写访问权限的函数。只需根据您想做的或想要的功能可以做的,使用正确的界面