Bonjour, Habr!
Je ne suis pas un expert très connu, mais je suis très intéressé par le processus de traitement des données, ainsi que par l'écriture de code pour traiter ces mêmes données. En train d'écrire diverses méthodes de traitement de ces mêmes données, j'ai eu l'idée d'une automatisation partielle, euh, des méthodes de traitement d'écriture.
introduction
Supposons que nous ayons un ensemble d'outils (entités) pour traiter une sorte de flux de données, ou construire d'autres entités complexes, ainsi que des conditions en constante évolution pour la séquence de composition de ces entités afin de reproduire l'algorithme de traitement.
Utiliser les véhicules comme exemple
Nous avons un ensemble de composants atomiques:
class EngineA;
class EngineB;
class WingsA;
class WingsB;
class FrameA;
class FrameB;
class WheelsA;
class WheelsB;
etc.
Si nous avons besoin d'une voiture, nous déclarons simplement la classe de voiture , qui a la carrosserie, les roues, le moteur, etc. De même avec un bateau, nous déclarerions une classe de bateau , et esquisserions rapidement l'agrégation des parties requises du bateau.
Si nous avons besoin d'un bateau, d'une voiture et même d'un avion, nous pouvons utiliser le modèle d'usine, mais que faire si nous avons besoin de voitures, de bateaux, d'avions et que nous ne savons pas à l'avance combien, quand et dans quel ordre .
, Car, Boat, Plane ITransport. 2 , 5 - . , , . -
, !
, ITransport
class ITransport
{
public:
virtual void move() = 0;
};
Car, Boat, Plane.
class Car final : public virtual ITransport
{
public:
Car() = default;
~Car() = default;
void move() override
{
std::cout << "Car is move" << std::endl;
// do something with parts
}
private:
std::unique_ptr < IFrame > _frame;
std::unique_ptr < IWheels > _wheels;
std::unique_ptr < IEngine > _engine;
};
class Boat final : public virtual ITransport
{
public:
Boat() = default;
~Boat() = default;
void move() override
{
std::cout << "Boat is move" << std::endl;
// do something with parts
}
private:
std::unique_ptr < IFrame > _frame;
std::unique_ptr < IEngine> _engine;
};
class Plane final : public virtual ITransport
{
public:
Plane() = default;
~Plane() = default;
void move() override
{
std::cout << "Plane is move" << std::endl;
// do something with parts
}
private:
std::unique_ptr < IFrame > _frame;
std::unique_ptr < IEngine> _engine;
std::unique_ptr < IWings > _wings;
};
2 , , 3 , .
, . .
enum class VehTypes
{
Car,
Boat,
Plane
};
static std::map < std::string, VehTypes > VehCast{
{"Car", VehTypes::Car},
{"Boat", VehTypes::Boat},
{"Plane", VehTypes::Plane}
};
, .
class Conveyor final
{
public:
using _TyParameters = std::map < std::string, std::string >;
using _TyStorage = std::vector < _TyParameters >;
Conveyor(const _TyStorage& blueprints)
: _blueprints(blueprints) { }
~Conveyor() = default;
std::vector < Vehicles::ITransport* > vehicles()
{
std::vector < Vehicles::ITransport* > result;
for (auto&& blueprint : _blueprints)
{
switch (VehCast[blueprint["type"]])
{
case VehTypes::Car: result.emplace_back(new Vehicles::Car());
break;
case VehTypes::Boat: result.emplace_back(new Vehicles::Boat());
break;
case VehTypes::Plane: result.emplace_back(new Vehicles::Plane());
break;
}
}
return result;
}
private:
_TyStorage _blueprints;
};
, .
:
-
- , .
using _TyParameters = std::map < std::string, std::string >;
using _TyStorage = std::vector < _TyParameters >;
, ( ).
, - , .
( ) .
.
.
Conveyor::_TyStorage blueprints
{
{
{"type", "Car"}, {"engineType", "EngineA"}, {"wheelsType", "WheelsB"}, etc..
},
{
{"type", "Car"},
},
{
{"type", "Boat"},
},
{
{"type", "Plane"},
},
{
{"type", "Plane"},
},
{
{"type", "Plane"}
},
{
{"type", "Boat"}
},
};
Conveyor conveyor(blueprints);
for (auto&& transport : conveyor.vehicles())
{
transport->move();
}
, , .
, , / .
Parmi les points faibles de cette approche de la construction d'objets, je peux noter la nécessité d'ajouter de nouveaux types au dictionnaire à chaque fois, ainsi que d'ajouter constamment l'interpréteur de nouveaux paramètres de texte si vous ajoutez constamment de nouveaux composants atomiques.