D
D
Dima Sokolov2018-05-13 12:31:25
C++ / C#
Dima Sokolov, 2018-05-13 12:31:25

How to implement factory method without switch?

How can you implement the "factory method" design pattern without using switch / multiple if / separate factories?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
E
Evgeny Shatunov, 2018-05-13
@dimka11

The factory method is the so-called. virtual constructor. There should be no choice constructs inside a function. The factory method itself is passed elsewhere to produce objects of some class with a particular interface.
Choice constructs are usually present inside abstract factories. A certain type identifier comes to the factory and (if the identifier is defined) the factory creates an object of some class with a certain interface.
An abstract factory can be implemented based on a container of factory methods. C++ templates and C++11/14 standards will only help us with this. The simplest code for such a factory might look like this:

Factory example
template< typename TInterface, typename... TArguments >
class AbstractFactory final
{
public:
  // Produce the implementation, but return the pointer to interface.
  inline std::shared_ptr<TInterface> Produce( const std::string& implementation_name, TArguments... arguments )
  {
    auto found_function = m_factory_functions.find( implementation_name );
    return ( found_function == m_factory_functions.end() )? std::shared_ptr<TInterface>{} : found_function->second( std::forward<TArguments>( arguments )... );
  };
  
  // Define the implementation.
  template< typename TImplementation >
  inline const bool DefineImplementation()
  {
    return DefineImplementation<TImplementation>( TImplementation::ClassName() );
  };
  
  // Define the implementation.
  template< typename TImplementation >
  inline const bool DefineImplementation( const std::string& implementation_name )
  {
    // Abort the incorrect registration.
    static_assert( std::is_base_of<TInterface, TImplementation>::value, "Implementation may only be derived from interface of Factory." );
    
    auto found_function = m_factory_functions.find( implementation_name );
    if( found_function == m_factory_functions.end() )
    {
      m_factory_functions[ implementation_name ] = &AbstractFactory<TInterface, TArguments...>::template ConstructImplementation<TImplementation>;
      return true;
    };
    
    return false;
  };
  
  // Check the implementation name is already defined.
  inline const bool IsImplementationDefined( const std::string& implementation_name ) const
  {
    return m_factory_functions.find( implementation_name ) != m_factory_functions.end();
  };
  
private:
  // The factory function just produce implementation.
  template< typename TImplementation >
  static std::shared_ptr<TInterface> ConstructImplementation( TArguments... arguments )
  {
    return std::static_pointer_cast<TInterface>(
      std::make_shared<TImplementation>( std::forward<TArguments>( arguments )... )
    );
  };

private:
  // Factory function produces the implementations of TInterface.
  using FactoryFunction	= std::shared_ptr<TInterface> (*)( TArguments... arguments );
  
  std::unordered_map<std::string, FactoryFunction>	m_factory_functions;
};

It works like this:
cpp.sh/93obm

E
eRKa, 2018-05-13
@kttotto

You answered your own question - factory method. The description and implementation of this pattern is available for all wiki
languages . As for the "separate factories", it's not entirely clear. The pattern itself abstracts the logic behind the decision to create an object. This logic is based on some kind of condition: switch / several if / separate factories. How you wrap this condition is your choice.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question