0

I'm new to OOP and design pattern.

I've a simple app that handles the generation of Tables, Columns (that belong to Table), Rows (that belong to Column) and Values (that belong to Rows). Each of these object can be a collection of Property, which is in turn defined as an enum.

They are all interfaces: I used factories to get concrete instances of these products.

Now I'm facing the problem of extending these classes. Let's say I need another product called "SpecialTable" which in turn has some special properties or new methods like 'getSomethingSpecial' or an extended set of Property. The only way is to extend/specialize all my elements (ie. build a SpecialTableFactory, a SpecialTable interface and a SpecialTableImpl concrete)? Let's say I would still like to use standard methods like addRow(column, name) that has no need to be inherited...

I don't like the idea to inherit factories and interface, but since SpecialTable has more method I guess it cannot share the same factory. Am I wrong?

Another question: if I need to define product properties at run time (a Table that is upgraded to SpecialTable), I guess I should use a decorator. Is it possible (and how) to combine both factory and decorator design?

halfer
  • 19,824
  • 17
  • 99
  • 186
Gabriele B
  • 2,665
  • 1
  • 25
  • 40

1 Answers1

4

SpecialTable needs its own creation mechanism, so yes, it will need its own factory method (or factory class, if you are creating a group of items that must be related).

Alternatively: You could use Design pattern Strategy for your factory. In that case you would configure the factory with the desired creation mechanism at runtime.

As for the remaining question:

The three most common ways to add functionality to a class are:

  1. Subclassing
  2. Design pattern Adaptor/Proxy, possibly combined with introspection. Categories are really a special case of this approach.
  3. Design pattern Visitor

You have already considered subclassing.

Design pattern Adaptor/Proxy is basically this: Create a new class that has the desired interface, and implements some (or all) of its methods by calling an instance of your existing class.

For Design pattern Visitor you in a sense combine Proxy with "Double Dispatch". Your added functions reside in an object that can call an instance of your existing class. See Visitor pattern - adding new ConcreteElement classes is hard? for an example.

Strategy:

It works like this:

public interface MyStrategyInterface {
  public void doWork();
}

public class MyStrategyAccessPoint implements MyStrategyInterface {

  private MyStrategyInterface current;

  public MyStrategyAccessPoint(final MyStrategyInterface initial) {
    current = initial;
  }

  public void doWork() {
    current.doWork();
  }

  public void setStrategy(final MyStrategyInterface newCurrent) {
    current = newCurrent;
  }
}

As you can see, you can now change which actual implementation of MyStrategyInterface is used at runtime. This pattern is often combined with Singleton, making MyStrategyAccessPoint and its doWork method static.

Community
  • 1
  • 1
Anders Johansen
  • 10,165
  • 7
  • 35
  • 52
  • tnx! your explanation was clear like fresh water and it seems that Visitor should be nice to use (I'm not sure i understood Strategy, to be honest). Let's say that table is a visitable object with an accept method and that SpecialBehaviour is a Visitor that identify a special table. I would use something like table.accept(specialbehaviour). But since this doesn't actually decorate table, I should then implements a method specialbehaviour.getSpecialTable to build a SpecialTable instance. Is this the correct way to use the pattern or am i wrong? – Gabriele B Nov 26 '12 at 23:39
  • 1
    Yes. With Visitor you don't decorate. The "decoration" is in the Visitor, in this case SpecialBehavior. Sometimes it's impossible or inconvenient to extend or subclass some classes, and Visitor offers an alternative. Case in point: If you were implementing a programming language that accesses a group of nodes (your basic class), you would have no way to know at compile time what code was written. Visitor would be the answer. The compiled code would be the Visitor... – Anders Johansen Nov 27 '12 at 08:25