Automating the creation of objects using a pipeline

Hello, Habr!





I am not some very famous expert, but I am very interested in the process of data processing, as well as writing code to process this very data. In the process of writing various methods of processing this very data, I had the idea of โ€‹โ€‹partial automation, ahem, writing processing methods.





Introduction

Suppose we have a set of tools (entities) for processing some kind of data flow, or building other complex entities, as well as constantly changing conditions for the sequence of composition of these entities to reproduce the processing algorithm.





Using vehicles as an example

We have a set of atomic components:





	class EngineA;
	class EngineB;

	class WingsA;
	class WingsB;

	class FrameA;
	class FrameB;

	class WheelsA;
	class WheelsB;
      
      



etc.





If we need a car, we simply declare the Car class , which has the desired body, wheels, engine, etc. Likewise with a boat, we would declare a Boat class , and quickly sketch out the aggregation of the required parts of the boat.





If we need a boat, a car, and even an airplane, we can use the factory pattern, but what to do if we need cars, boats, airplanes, and we do not know in advance how many, when, and in what order.





, 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();
}
      
      







, , .





, , / .





Of the weak points of this approach to constructing objects, I can note the need to add new types to the dictionary every time, as well as constantly add the interpreter of new text parameters if you constantly add new atomic components.








All Articles