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?
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.
Say we take the option
Make Loader a friend of Resource.
With the drawback
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.
However, since you split your loaders into a base class + derived classes, you can just grant access to Loader
, and give Loader
subclasses access through protected
members.
class Resource
{
Type1 InternalData1;
...
friend class ResourceLoader;
};
class ResourceLoader
{
...
protected:
static void setResourceInternalData1(Resource &r, const Type1 &val1);
...
};
All ResourceLoader
subclasses can now access these setters because they are protected
:
class ResourceLoaderFormat1: public ResourceLoader;
class ResourceLoaderFormat2: public ResourceLoader;
This will work well as long as you don't change the data members of Resource
too often.