Как стать автором
Обновить

Вычисление динамических объектов по вектору

Время на прочтение 3 мин
Количество просмотров 2.5K

Введение

Допустим, у нас есть набор объектов с некими данными, и нам нужно произвести манипуляции с этими объектами.

Положим, самый обычный пример - наполнить корзинку фруктами. Мы реализуем некий класс Сart, в который будем складывать фрукты. Далее нам понадобиться базовый класс Fruit, для того, чтоб определить параметр объема, которому мы будем присваивать значение в зависимости от фрукта. Задача решена, фрукты складываются до тех пор, пока объем корзинки не достигнет порога.

После нескольких итераций, когда наша программа, по наполнению корзинок, сложила несколько сгнивших груш, яблок с червями или еще что-нибудь пошло не так, мы расширим базовый класс Fruit, добавив в него параметры свежести, чистоты и т.д., пока будут появляется новые условия проверки.

И вот тут начинается проблема. Да, наш класс стал более универсальным, но увеличиваться может не только количество проблем с фруктами, но и сами ситуации сбора фруктов могут быть различными. Например, мы собираем фрукты там, где абсолютно каждый плод будет свежим. Зачем, в таком случае, нам поле, отвечающее за свежесть, если все фрукты заведомо свежие? Городить лишний функционал, для указания обязательных и не обязательных типов? - нет конечно. Мы выносим ряд опциональных типов в массив(словарь), где каждый тип не является непосредственной частью класса. Наш функционал снова стал умнее, отлично.

Однако, я решил пойти дальше, и немного развить эту тему.

Идея

Мы определяем тип, который будет отвечать за хранение опциональных переменных в строковом формате. Фактически, это обертка над массивом. В качестве минимального набора информации будем хранить название переменной, тип(это может быть как базовый, int, string, bool, так и композиция из нескольких базовых) и значение.

Методы у данного объекта могут быть вариативными, но я для себя выделил следующие:

  • получение списка переменных и их типов в строковом формате(в целом, можно ограничиться названиями). Это может пригодится если мы какой-то объект захотим отметить "началом координат".

  • геттер, который возвращает наш массив с информацией о переменных в формате константы.

  • получение id типа и значение по названию переменной(понадобиться для каста в конкретный тип).

class IVariable
{
	public:

		using Type = std::variant < int, double, bool, std::string>; // для удобства каста типов 
				 

		virtual std::vector < std::pair < std::string_view, std::string_view > > abstract() = 0;
				  
		virtual std::vector < std::tuple < std::string_view, VarTypes, std::string_view > > released() = 0;

		virtual std::pair < VarTypes, std::string_view > released(const std::string_view& name) = 0;

				    
};

Теперь, когда у нас все опциональные параметры обособлены в отдельный тип, мы можем проделать следующее:

  • Имея набор все тех же фруктов, проверить параметр "свежесть" у каждого фрукта, предварительно построив вектор только из этого параметра.

Вспомогательная функция, которая просто проверяет наличие конкретного параметра у массива наших "расширенных" переменных

bool tryVector(const std::string_view& dX)
{
	auto type = range.front()->released(dX); 

	if(type.first == VarTypes::_null) 
	{
    	return false;
	}

	for(auto&& var : _range)
	{
		if(var->released(dX).first != type.first) 
 		{
			return false;
		}
	}

	return true;  
}
  • Или наоборот, построить вектор сразу из нескольких параметров(скомбинировать несколько вызовов tryVector).

Вообще говоря, вспомогательных функций может быть и больше, но для примера я ограничился одной, дабы не захламлять статью.

Мотивация

  • Возможность оперировать с данными набора объектов, не имея информации о базовом типе, или вообще не имея базового типа.

  • Возможность регулировать скоуп работы с объектами, когда, в зависимости от ситуации, нам нужно либо больше параметров, либо наоборот меньше.

  • Думать не над тем, как спроектировать объект, а над тем, какие действия должны совершаться с объектом

Недостатки

  • Не подходит для расчета большого количества однотипных объектов. Скажем, для какого-нибудь класса, определяющего rgb составляющую пикселя - эффективнее будет явно определить свойства.

  • Подобный подход будет потреблять достаточно много памяти, и соответственно имеет смысл использовать его только для работы с объектами, суть которых нельзя выразить через несколько простых переменных, т.е. больше для логической обработки объектов, нежели прямых расчетов.

Теги:
Хабы:
+3
Комментарии 37
Комментарии Комментарии 37

Публикации

Истории

Работа

Программист C++
121 вакансия
QT разработчик
13 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн