Introdução
Digamos que temos um conjunto de objetos com alguns dados e precisamos manipular esses objetos.
Digamos que o exemplo mais comum seja encher uma cesta com frutas. Implementaremos uma certa classe art, na qual adicionaremos frutas. Em seguida, precisamos da classe base Fruta, para definir o parâmetro de volume, ao qual atribuiremos um valor dependendo da fruta. O problema está resolvido, as frutas são adicionadas até que o volume da cesta atinja o limite.
Depois de várias iterações, quando nosso programa, para encher cestas, dobrou algumas peras podres, maçãs com vermes ou algo mais deu errado, iremos estender a classe base de frutas, adicionando parâmetros de frescor, pureza, etc. a ela, enquanto nova condições de verificação aparecem.
E é aí que começa o problema. Sim, nossa aula se tornou mais versátil, mas não só o número de problemas com frutas pode aumentar, mas as próprias situações de colheita de frutas podem ser diferentes. Por exemplo, nós escolhemos frutas onde absolutamente todas as frutas são frescas. Por que, nesse caso, precisamos de um campo responsável pelo frescor, se todas as frutas são sabidamente frescas? Para cercar funcionalidade extra para indicar tipos obrigatórios e opcionais? - Claro que não. Colocamos vários tipos opcionais em um array (dicionário), onde cada tipo não faz parte diretamente da classe. Nossa funcionalidade é mais inteligente novamente, ótimo.
No entanto, decidi ir mais longe e desenvolver um pouco este tópico.
Ideia
Definimos um tipo que será responsável por armazenar variáveis opcionais em formato de string. Na verdade, é um invólucro sobre uma matriz. Como um conjunto mínimo de informações, armazenaremos o nome da variável, o tipo (pode ser basic, int, string, bool ou uma composição de várias variáveis básicas) e o valor.
Os métodos deste objeto podem ser variáveis, mas eu destaquei o seguinte para mim:
obter uma lista de variáveis e seus tipos em formato de string (em geral, você pode se limitar a nomes). Isso pode ser útil se quisermos marcar algum objeto com a "origem".
getter que retorna nosso array com informações sobre variáveis em formato constante.
obtendo o id do tipo e o valor pelo nome da variável (necessário para converter para um tipo específico).
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).
, , , .
, , .
A capacidade de ajustar o escopo de trabalho com objetos, quando, dependendo da situação, precisamos de mais parâmetros, ou vice-versa, menos.
Não pense em como projetar um objeto, mas em quais ações devem ser realizadas com o objeto
desvantagens
Não é adequado para calcular um grande número de objetos do mesmo tipo. Por exemplo, para alguma classe que define o componente rgb de um pixel, será mais eficiente definir explicitamente as propriedades.
Tal abordagem consumirá muita memória e, portanto, faz sentido usá-la apenas para trabalhar com objetos, cuja essência não pode ser expressa em termos de várias variáveis simples, ou seja, mais para processamento lógico de objetos do que cálculos diretos.