Как реализовать фабричный метод без switch?

Как можно реализовать паттерн проектирования "фабричный метод" без использования switch / нескольких if / отдельных фабрик?
  • Вопрос задан
  • 1134 просмотра
Решения вопроса 1
@MarkusD Куратор тега C++
все время мелю чепуху :)
Фабричный метод - это т.н. виртуальный конструктор. Внутри функции не должно быть конструкций выбора. Сам фабричный метод передается в другое место для порождения объектов некоторого класса с определенным интерфейсом.

Конструкции выбора обычно присутствуют внутри абстрактных фабрик. В фабрику приходит некий идентификатор типа и (если идентификатор определен) фабрика создает объект некоторого класса с определенным интерфейсом.

Абстрактную фабрику можно реализовать на основе контейнера фабричных методов. Шаблоны C++ и стандарты C++11/14 нам в этом только помогут. Самый простой код такой фабрики может выглядеть вот так:
Пример фабрики
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;
};


Работает она примерно так:
cpp.sh/93obm
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@kttotto
пофиг на чем писать
Вы же сами ответили на свой вопрос - фабричный метод. Описание и реализация этого паттерна есть для всех языков вики
По поводу "отдельных фабрик" не совсем понятно. Сам по себе паттерн абстрагирует логику принятия решения о создании объекта. Эта логика основана на каком то условии: switch / нескольких if / отдельных фабрик. Во что Вы обернете это условие - Ваш выбор.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы