2

I try to understand the SOLID principles and therefore implemented some java snippets. My concern is the OCP at the moment. Having following samples,

public abstract class Bakery
{
 public abstract Bakegood bake();
}

/******************************************/

public class BreadBakery extends Bakery {
 @Override
 public Bakegood bake() {
    return new Bread();
 }
}

/******************************************/

public class CakeBakery extends Bakery {
 @Override
 public Bakegood bake() {
    return new Cake();
 }
}

/******************************************/

how can I create the right bakery. Assume a customer comes to the bakery and says: "I'd have two cakes, please!", how can I then instantiate the CakeBakery. Of course I can create an abstract factory like:

public static Bakery createBakery(final String orderedBakegood)
{
 switch(bakegood)
 {
  case "Cake": return new CakeBakery();
  case "Bread": return new BreadBakery();
  default: throw new InvalidBakeryException();
 }
}

But I don't want to use switch or if statements. Is there any other possibility or am I completely wrong with the understanding?

pgiecek
  • 7,970
  • 4
  • 39
  • 47
Arthur Eirich
  • 3,368
  • 9
  • 31
  • 63
  • 1
    What's wrong with switch or if statements? You need to make a decision somehow. – Philipp Mar 15 '16 at 09:11
  • The switch could work, but you need to make it open for extension. Meaning you should be able to override it, so the method should not be static. Another solution is reflection, it's more flexible. I'd like to see what others have to say about this, I've faced this issue too. – Filkolev Mar 15 '16 at 09:15
  • 3
    @Filkolev Considering that he's trying to adhere to good standards and patterns, using reflection here would be like shooting yourself in the face because you want to paint your wall. – Kayaman Mar 15 '16 at 09:28
  • @Kayaman I couldn't object any better :) – Arthur Eirich Mar 15 '16 at 09:30
  • Can you guys support your claim that reflection is a bad coding practice in this particular case? – Filkolev Mar 15 '16 at 09:38
  • @Filkolev Reflection is imho like a backdoor to extract all the information even out of a final class. I mean if a class is declared final by design it means that a class must not have any subclasses and all the fields/methods of this class must not get accessed/overridden by some other code. Reflection allows you to do that and it is against the actual purpose of `final` modifier. – Arthur Eirich Mar 15 '16 at 09:48
  • Wouldn't this question be best suited for [ProgrammersSO](http://programmers.stackexchange.com/) ? – Spotted Mar 15 '16 at 10:02
  • @Spotted It is about an implementation of opened/closed priciple in Java. I think SO is OK. – pgiecek Mar 15 '16 at 10:23
  • @Spotted when referring other sites, it is often helpful to point that [cross-posting is frowned upon](http://meta.stackexchange.com/tags/cross-posting/info) – gnat Mar 15 '16 at 10:29

2 Answers2

3

Open/closed principle says:

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

So whenever you introduce a new Bakery, you should not modify existing code. You can use something like a registry for your Bakery classes. If you need to add a new Bakery, just extend Bakery class and register it (e.g. at startup). Hence no "if" or "switch" modification is required. Moreover, adding a new Bakery does not require changing the internals of the registry or the code that is calling the registry.

Furthermore, this technique is not dependent on the way you register your components. You can do it programatically, with a configuration file (xml, ...), via classpath scanning, ...

You can see this approach in the Spring framework a lot. Basically the Spring framework is a great source of many design principles.

Here you can see a very simple registry implementation.

public class BakeryRegistry {

    private Map<String, Bakery> mapping = new HashMap<>();

    public BakeryRegistry() {
        loadDefaultMappingFromConfigFile();
    }

    public Bakery getBakery(String name) {
        return mapping.get(name);
    }

    public void registerBakery(String name, Bakery bakery) {
        mapping.put(name, bakery);
    }

    private void loadDefaultMappingFromConfigFile() {
        ...
    }
}

Maybe article Killing Switch Statements With A Registry can help. It is based on JavaScript but the principle is the same.

pgiecek
  • 7,970
  • 4
  • 39
  • 47
0

The contrived abstraction is causing the problem here. Customers will not ask the bakery for abstract "baked goods", because all baked goods are not substitutable. Bread is not a substitute for cake, and vice versa. Wrapping these two different products into one inheritance hierarchy is a violation of the Liskov Substitution Principle.

The SOLID principles are interrelated, so applying OCP will be difficult or impossible without applying LSP first. See the introduction to LSP where Robert Martin describes inheritance as being critical to OCP, and goes on to describe LSP as being critical to inheritance.

jaco0646
  • 15,303
  • 7
  • 59
  • 83