删除“工厂”< - >“具体实现”依赖项

I have a "provider factory" which creates an implementation of a concrete provider. To create correct implementation it needs, among other parameters, typeId. The problem is that in order to pass the correct typeId to the factory, I need to validate and, if necessary, change it. And in order to do that, among other parameters, I need an instance of a particular provider. Which is where the problem is - the provider should be singleton (I really don't want to make it a Singleton with a capital S), because it queries a database and caches the result in the internal property.

So my question is - is there a more suitable pattern to use or another way to achieve something similar?

class ProviderFactory
{

    public function createProvider($typeId)
    {
        if ($typeId == 2) {
            return new Provider2($arg1, $arg5);
        } elseif ($typeId == 4) {
            return new Provider4();
        } else {
            return new ProviderDefault($typeId, $arg1, $arg2, $arg3, $arg4);
        }
    }
}


interface ProviderInterface
{
    public function getCost();
}

class ProviderDefault implements ProviderInterface
{
    public function __construct($arg1, $arg2, $arg3, $arg4) {}

    public function getCost() { /*implementation*/ }
}

class Provider2 implements ProviderInterface
{
    public function __construct($arg1, $arg5) {}

    public function getCost() { /*implementation*/ }
}

// this call can be implemented with the following condition
// if ($typeId == 2) {
//      if ($provider2->getCost() !== null)
//          $typeId = 1;
// }
//
$typeId = fixAndValidateTypeId($typeId, new Provider2($arg1, $arg5));


$factory = new ProviderFactory();
$provider = $factory->createProvider($typeId);

I suggest you to implement ChainOfResponsibility pattern in ProviderFactory, so that you don't need to modify ProviderFactory each time new Provider is added or logics changed. You just need to add RegisterProvider(IProvider provider) method to add providers in chain and then just cycle through this chain of providers calling bool:DoesProviderSuit(int typeId, out IProvider) of each IProvider.

Hope you catch an idea, good luck!