In my project I have Resource objects which can be loaded and reloaded from different formats. Loading algorithms are implemented in different ResourceLoader subclasses.
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 reads input in a given format and initializes its target Resource object R. Loader is stored inside a resource, so if resource becomes invalid, it reloads itself using the loader stored.
The question is how a Loader should initialize a Resource?
- Make all InternalData fields public. It grants client access to them, which is not good.
- 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.
- Provide setter for each InternalData. Not far from making all them public, as any client may change data it must not change.
- Provide Resource::Setup(InternalData1, InternalData2, InternalDataN), or wrap them all in some structure and pass that structure. Same as 3. except that all fields are set at a time.
The problem is that a Resource class fields must be accessible for write from extensible set of classes and must be inaccessible for write from a client code. Is there any good OOP solution? Thanks.