Yes, SpecialTable
can be produced by the same factory (and by the same factory method) that produces Table
. This not a problem, as long as SpecialTable
provides at least the methods guaranteed by the Table
interface (which it does).
This sort of situation makes sense when objects returned from the factory have some guaranteed behaviour/functionality (interface Table
), and some optional stuff (interface SpecialTable
).
So, in order to make use of the optional extra abilities/stuff available on some concrete objects returned by the factory, you have a few choices:
use polymorphism (recommended)
make use of instanceof
(or similar), which can be used to check for interface compliance/exact typing (avoid this if possible!)
Using polymorphism
An example to illustrate: suppose SpecialTable has extra data and an extra widget 'blarg' which appears on the UI representing special tables. Do you really need the code which uses SpecialTable to know that it needs to add 'blarg' to the UI? Or can you just have your external code ask the thing of type Table to add its necessary UI components to some UI container? Then the calling code doesn't care what exact type the thing is -- SpecialTable deals with it, adding the 'blarg' to the container itself. This pattern can be described as the delegate pattern (also sometimes also known as strategy pattern).
Using instanceof (type checking)
Example of instanceof
use:
// Table and SpecialTable are interfaces
Table table = TableFactory.instance().getDefaultTable();
if (table instanceof "SpecialTable") {
SpecialTable specialTable = (SpecialTable)table;
specialTable.specialMethod();
}
table.normalMethod();
Note that when you define your SpecialTable
interface you can declare it as extending the Table interface and then only list the extra methods.
Your factory will be producing concrete objects of either type. So you might have a concrete class called BoringTable
which implements Table
, and a concrete class called ExcitingTable
which implements SpecialTable
.
Beware instanceof!
It's generally better to avoid things like 'instanceof' (or generally speaking, ifs of any kind which depend on what type an object is). You should favour polymorphism instead. By this I mean having multiple different classes, of a common type, enclosing different behaviour in their implementation code.
Ask yourself this: does the class using something of type Table
(which might also be of type SpecialTable
) need to care if it's a special table or not? Can you not hide that distinction in some sort of implementation of the SpecialTable -- have it do something different, something extra, that plain old Table does?
Why would you separate your factory from the object-type it creates?
public class Foo {
// Private constructor
private Foo(...) {...}
public static Foo of(...) { return new Foo(...); }
}
This is what Joshua Bloch describes as his Item 1 on page 5 of his book, "Effective Java." Java is verbose enough without adding extra classes and singletons and whatnot. There are some instances where a separate factory class makes sense, but they are few and far between.
To paraphrase Joshua Bloch's Item 1, unlike constructors, static factory methods can:
- Have names that can describe specific kinds of object creation (Bloch uses probablePrime(int, int, Random) as an example)
- Return an existing object (think: flyweight)
- Return a sub-type of the original class or an interface it implements
- Reduce verbosity (of specifying type parameters - see Bloch for example)
Disadvantages:
- Classes without a public or protected constructor cannot be subclassed (but you can use protected constructors and/or Item 16: favor composition over inheritence)
- Static factory methods do not stand out from other static methods (use a standard name like of() or valueOf())
Really, you should take Bloch's book to your code reviewer and see if the two of you can agree to Bloch's style.
Best Answer
Factory is probably one of the most misused patterns. People always talk about how it allows to easily switch to a different factory that generates different classes, but usually fail to notice that you can't do that with factory alone - you need some sort of dependency injection too!
The overhead seems small - use
CalendarFactory.newInstance().newCalendar()
instead ofCalendar.getInstance()
. But we wanted factory in the first place so we could easily switch factories and change the way objects are constructed. Can we really do that here?CalendarFactory.newInstance()
is always the same function so it'll always return a factory object constructed the same way, which will createCalendar
s in the same way. In order to change theCalendar
creation process, we need to either changeCalendarFactory.newInstace
orCalendarFactory.newCalendar
. How is that any better from having to changeCalendar.getInstance
?If we want to be able to easily change the
Calendar
creation process, we had to use dependency injection - create aCalendarFactory
object somewhere and pass it around. That way we can control which factory the methods we call and objects we construct use.There is a drawback to this approach though - having to pass that factory object around introduces quite a burden on the programmer. Methods need an extra arguments - for the entire call-chain from where the factory is created to where it's used. Objects need an extra field that you need to supply even if you don't use any method that requires that factory(alternatively - you have to remember if you supplied it or not, and exception will be thrown if the factory field is not set. But this exposes the implementation as it forces the user to know which methods require setting the factory field).
Since the overhead here is much bigger than the naive, worthless use of the factory, we can't just blindly apply the pattern(OK, I take that back - you can always blindly apply design patterns, and too many programmers do) and we actually need to think. Do we really need to be able to switch the
Calendar
creation process all over the place? Do we need it enough to introduce such burden on the programmers?In the case of Java's
Calendar
, the answer was "no". Being able to tell what the time is differently, or to represent it differently in the memory, is not useful enough to have to pass around aCalendarFactory
object all over the place.