инициализация — инициализация объекта от другого в переполнении стека

В моем проекте у меня есть объекты 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 должны быть доступны для записи из расширяемого набора классов и должны быть недоступны для записи из клиентского кода. Есть ли хорошее решение ООП? Благодарю.

2

Решение

Скажем, мы берем вариант

Сделайте 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 слишком часто.

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 использует правильный интерфейс в зависимости от того, что вы хотите сделать или хотите, чтобы функция была в состоянии сделать

1

По вопросам рекламы [email protected]