-1

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.

Saint
  • 5,397
  • 22
  • 63
  • 107
  • I suppose you need two different factory-methods, one with the parameter within `MyProductFactory` and the other without parameter within `YourProductFactory`. This means the factory won´t even derive from `ProductFactory` at all. – MakePeaceGreatAgain Apr 12 '17 at 14:43
  • @HimBromBeere then it's not factory related design pattern. I'm not saying it has to be this one, but I stronlgy belive it's possible to achieve it in compliance with any design pattern :) – Saint Apr 12 '17 at 14:45
  • @Saint, What makes you think it's wrong? – OfirD Apr 12 '17 at 16:20
  • 1
    Sounds like a leaky abstraction. Parameters you provide should be required for both types that factories create. If you need to customize other aspects of those types consider to provide those distinct values (or providers of those values) to factory constructors. Let me know if you want to see an example. – Andrii Litvinov Apr 12 '17 at 17:07
  • @AndriiLitvinov If you can please provide some example. But one more thing: Factories are also injected in c-tors of theirs client class. – Saint Apr 12 '17 at 18:10
  • @HeyJude downvote from you? Anyway, I mean what AndriiLitvinov mentioned - all derived classes should know what to do with passed argument. In this case it's not used at all. It's not opinion based, since it's based on common good practices. If you do: string one = 1.ToString() it's also wrong, and again it's not opinion based. However I don't want to discuss here about wrong vs correct, rather than another solution for it – Saint Apr 12 '17 at 18:15

2 Answers2

1

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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Yes, I'm not using patterns just because of using them. I'm considering to get rid of abstraction since this example seems not suit to the rule. I was wondering if I missed something about factory related patterns. – Saint Apr 13 '17 at 06:34
  • Thanks for your answer. Please see my update in question – Saint Apr 13 '17 at 06:54
0

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.

Community
  • 1
  • 1
Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59
  • Actually it's not good approach in this case. Product will differ for each call Create method. For this simplified example sometimes will be true, sometimes false. Additional service also doesn't have knowledge about the details as it comes directly from UI. I'm wondering whether it's possible to use abstract factory here at all. – Saint Apr 13 '17 at 06:30
  • It is possible, but again, consumer of the factory will know too much of the concrete factory requirements which is leaky abstraction. So I wouldn't suggest for abstract factory approach. Regarding the thing that boolean parameter will change for every request you can create new factory for every request with new parameter. But you should probably look at strategy pattern as well. – Andrii Litvinov Apr 13 '17 at 07:10