Search code examples
javaoopdesign-patternscoding-styleapex

Factory Pattern or Extended Method?


I am studying Design Patters and I have a situation where I am not sure what would be a better practice:

I have a class "Category" which has several fields: name, 2 kinds of urls, list of related objects. There is a method 'toHtml()' which basically generates some HTML from instances of that class.

There are 4 different types of 'Categories' which have exactly the same fields but 'toHtml()' method should give different result for each one.

I am not sure if I should pass a parameter "type" and series of ifs/switch statement to generate different html or should I make a Category class abstract and create several sub-classes that override the toHtml() method and then use CategoryFactory class to generate them? In both cases I need to pass 'type' parameter.

I tried to think about 'Close for modification, open for extension' OOP rule. But in this case if I want to add 'fifth' category type, that generates different html - for first solution I need to modify only toHtml method (adding one more if), going for second solution I need to create additional sub-class AND modify CategoryFactory class.

What would be better practice? Is there any extra rule I should follow when I have similar kind of dilemma?


Solution

  • First, I believe you are referring to the Factory Method, and not the Abstract Factory Pattern.

    The main difference being, in the former you define a common template for a single product, whereas in the latter you define a template for a family of products. For more information, you could look here.

    In your case, you wish to define a template for Category. With this assumption, here is what your group of classes would look like:

    abstract class Category {
        public void doSomething() {
            Foo f = makeFoo();
            f.whatever();   
        }
    
        abstract void toHtml();
    }
    
    class Category1 extends Category {
        public override void toHtml() {
            ... // do something here
        }
    } 
    
    class Category2 extends Category {
        public override void toHtml() {
            ... // do something else here
        }
    } 
    

    It is true that this certainly a lot of code, and could easily be represented like this:

    class Category {
        public void toHtml(Integer param) {
            if(param == 1) { // do something for Category1
            }
            else { // do something for Category2
            }
        }
    

    At the end of the day, it really is a design decision. There are some factors you can consider. Is this going to be a constantly changing class? Is this going to be declared global for the customer to use? How do you want the customer to be able to use this?

    The easier thing at this point would be to take the path of least resistance. Having one class to service all categories certainly results in lesser code and in Salesforce, less code is always a better thing. But consider this: Abstracting your functionality into separate classes makes for more maintainable code. You may find it easier to write a class and a wall of if statements, but tomorrow when you're not around and there's a critical failure and someone has to look through your code to figure out exactly which if caused the problem, they'll curse you for it.

    Keep in mind that inheritance is an all or nothing mechanism. You may find it particularly useful to use if you have some common functionality, in which case you can choose to abstract that out into the parent class and have your children take care of the specifics.