Parametrized Abstract Factory / Factory Method / other creation patterns

1.9k Views Asked by At

I want to have some factory (doesn't matter if Abstract Factory pattern or Factory Method - looks like the second is specific form of the first one. In my case only one object should be created). The thing is that although created products are similar, they depends on some arguments.

How to prepare this architecture in compliance with design patterns?

Current approach below

public abstract class Product {}

public class MyProduct : Product
{
    public bool Abc { get; set; }
}

public class YourProduct : Product {}

public abstract class ProductFactory
{
    //in some cases parameter not in use
    public abstract Product Create(HelpData additionalData);
}

public class MyProductFactory : ProductFactory
{
    public override Product Create(HelpData additionalData)
    {
        return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
    }
}

public class YourProductFactory : ProductFactory
{
    //unused parameter
    public override Product Create(HelpData additionalData)
    {
        return new YourProduct();
    }
}

public class HelpData
{
    public bool SomethingImportantForMyProduct { get; set; }
}

EDIT

I see it's not clear so will repeat.

Usually I'm not using patterns just because of using them. But this problem seems not to be border case. Looks rather quite frequent. Going further I believe there's design pattern suitable to this, but I'm not sure which one. For now looks like abstract factory is not right choice.

2

There are 2 best solutions below

2
MakePeaceGreatAgain On BEST ANSWER

Don't use design-patterns because you're using design-patterns. Always have in mind when to use one and when not. In your circumstances at least the abstract factory-pattern is wrong, as it assumes all factories to work with the same parameters. So if you have different parameters you surely need different factories.

However there's no way for the abstract factory to guess how to get an instance of a HelpData in some case but not in the other, so either pass it to every abstract factory or completely omit this further abstraction and stay with two independent factories:

public abstract class Product {}

public class MyProduct : Product
{
    public bool Abc { get; set; }
}

public class YourProduct : Product {}

public class MyProductFactory
{
    public Product Create(HelpData additionalData)
    {
        return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
    }
}

public class YourProductFactory
{
    //unused parameter
    public Product Create()
    {
        return new YourProduct();
    }
}

public class HelpData
{
    public bool SomethingImportantForMyProduct { get; set; }
}

Exposing a parameter only used within one factory to all factories isn't a good idea.

Besides this just imagine you don't have factories but any other classes that have a Create-method, where one needs a parameter, but the other one does not. Why should those two classes derive from the same base-class (in your case the abstract factory), when the don't have any common members? There's apparently no reason for this, so don't overcomplicate things just for the sake of using a pattern which doesn't fit.

2
Andrii Litvinov On

Depending on where and how you retrieve additional data you could inject that data to the factory which will use it to construct the object:

public abstract class ProductFactory
{
    public abstract Product Create();
}

public class MyProductFactory : ProductFactory
{
    private HelpData additionalData;

    public MyProductFactory(HelpData additionalData)
    {
         this.additionalData = additionalData;
    }

    public override Product Create()
    {
        return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
    }
}

public class YourProductFactory : ProductFactory
{
    public override Product Create()
    {
        return new YourProduct();
    }
}

Instead of passing HelpData to constructor of a factory you could inject a service that knows how to retrieve HelpData specific to the object being created. You could pass some other parameter to Create method if it is used for both factories.

I have also googled a bit and found good answer that explains why not https://stackoverflow.com/a/6241219/2138959. Passing a dictionary or a type that has property of dictionary type is also and option but in such approaches client has too much knowledge of a type it want to be created to use abstract factory.