Artem Altukhov
Artem Altukhov

Reputation: 3

What is the best way to use matching patter (switch) in factory methods

I want to create objects using constructions like this:

IProduct product1 = creator.CreateProduct<ConcreteProduct1>();
IProduct product2 = creator.CreateProduct<ConcreteProduct2>();

My version of the CreateProduct method looks like this:

public T CreateProduct<T>()
        where T: IProduct, new()
    {
        switch (typeof(T))
        {
            case(...) return new ConcreteProduct1;
            case(...) return new ConcreteProduct2;
        }
    }

My problem is, that I don't know how to use the matching pattern in this case. I tried a couple of options:

case (typeof(ConcreteProduct1)): return new ConcreteProduct1;
case (ConcreteProduct1 c): return new ConcreteProduct1;

But all of these don't work.

What expressions I should use in the case statements? Or what other options I have to implement this method?

Upvotes: 0

Views: 79

Answers (2)

jsami
jsami

Reputation: 356

The scenario where it is useful to do that is when we want to achieve loose coupling between components of the application and only manipulate interfaces without knowing which implementation is currently instantiated. For example, let's say we have the interfaces below:

interface IProduct
{
}

interface IArticle
{
}

And let's say those interfaces have the implementations below:

class ConcreteProduct1: IProduct
{
}

class ConcreteProduct2: IProduct
{ 
}

class ConcreteArticle1: IArticle
{
}

class ConcreteArticle2: IArticle
{
}

Now, in the client part of the codebase, we want to manipulate IArticle and IProduct without knowing which implementation is currently instantiated, something like:

static void Main()
{
  var article = Factory.Create<IArticle>();
  var product = Factory.Create<IProduct>();
}

And, the Factory would look like this:

public static class Factory
{
  public static T Create<T>() where T : class
  {
    return Activator.CreateInstance(ImplementationOf<T>()) as T;
  }

  public static Type ImplementationOf<T>()
  {
    // Concrete types registration
    var map = new Dictionary<Type, Type>()
    {
      [typeof(IArticle)] = typeof(ConcreteArticle1),
      [typeof(IProduct)] = typeof(ConcreteProduct2)
    }


    return map[typeof(T)];
  }
}

Here, the Factory.ImplementationOf method contains the mapping between an interface and the concrete type to use at runtime. And, in the future, if we want to switch to another implementation of an interface, like ConcreteArticle2 for IArticle, we only need to modify this method without touching client codes.

Upvotes: 0

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23228

If ConcreteProduct1 and ConcreteProduct2 classes implement IProduct interface, you don't need any switch expressions, just simple return a new instance (since you've passed the required type as generic type parameter T and generic type constraint for parameterless constructor)

public T CreateProduct<T>()
    where T: IProduct, new()
{
    return new T();
}

Upvotes: 1

Related Questions