0

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?

x1r15
  • 17
  • 4
  • I would make the category class abstract, extend it for each type and have each of your types do their own toHTML(). I would advise against creating a default toHTML() in your abstract class and force the classes implement their own. – RAZ_Muh_Taz Jun 22 '17 at 22:26
  • Thank you so much @RAZ_Muh_Taz for your advice! – x1r15 Jun 23 '17 at 12:24

2 Answers2

0

If you create a subclass of Category and override the toHtml () method, why do you need to have a factory pattern. The toHtml () method of the runtime resolved class will be called if you are calling it using the reference. This implies that if you add a new Category subclass then you override the toHtml () method and it should work fine.

Sachin Kumar
  • 808
  • 3
  • 11
  • 29
  • Different sub-classes will be instantiated in various places. Because of that I try to avoid creating them directly as it would mean making 'the same decision' in every place where I need to create the objects. – x1r15 Jun 23 '17 at 12:26
0

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.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • Thank you very much for thorough answer. You have been very helpful. :) – x1r15 Jun 23 '17 at 12:23
  • @x1r15: Coming from an sf background, I know what you're going through since I've been in the same situations before. At the end of the day I decided to bite the bullet and write those extra classes, and it hasn't hurt me since. :) Cheers. – cs95 Jun 23 '17 at 12:33