factory should return shared_ptr