In the case of generic type variables the compiler doesn't actually care if T
is a class, an interface, an enum or an annotation. All it cares about is that it is a type with a given set of sub- and super-types.
And there is no reason to complicate the syntax just because in one other place (where you actually implement an interface) the distinction between classes and interfaces is relevant (for example if you implement
an interface, you need to implement all methods it defines, but you don't need to, if you extend
a (non-abstract) class).
Assuming for a moment that you'd have to write implements
here, then you'd also need a separate syntax for enum
values (instead of simply writing <E extends Enum<E>>
) and annotations (which you can easily declare using <A extends Annotation>
).
The only place where you need to write implements
is at the point where you actually implement the interface. At that point (and that point only) the difference is important, because you must implement the methods defined in the interface. For everyone else, it doesn't matter if any given A
is a base class or an implemented interface of B
: it's a super-type and that's all that matters.
Also note that there's one other place where you use extends
with interfaces:
interface A {
}
interface B extends A {
}
At this point implements
would be wrong, because B
does not implement A
.
The Design Patterns book is descriptive, not prescriptive; it describes the patterns the GoF have observed in the wild; patterns that solve problems.
Some problems can be solved in more than one way.
The alternative you describe is also my preferred approach, but it's also described in the book: it's a combination of the Abstract Factory and Strategy patterns. You use an Abstract Factory as a Strategy.
I don't understand why one would go through the trouble of subclassing a class and making it abstract just for the benefit of allowing it to use a factory in a loosely-coupled manner.
For the exact same reason that you would combine Abstract Factory and Strategy. However, the best solution partly depends on your language.
If, for example, you were programming in Eiffel, Factory Method would probably be easier, because Eiffel has multiple inheritance, but (IIRC) no interfaces.
Also, if you're using a language where you can create a derived value on the spot (such as Java or F#), Factory Method might actually be easier than the Abstract Factory/Strategy combo.
Best Answer
Interfaces are unrelated to Design Patterns. They are about Object-Orientation. In OO, the type of an object is defined by its behavior, i.e. by the protocol it speaks (its methods).
Classes in languages like Java and C#, however, also define representation (fields) in addition to behavior (methods). One of the basic tenets of OO is that objects cannot know the representation of other objects even of the same type. However, if you use classes as types, other objects of the same class can know the representation of other objects, even
private
fields. Therefore, using classes as types breaks OO. (Unfortunately, in both Java and C#, classes are types.)The only way to do object-oriented programming in Java or C# is to use classes only as factories (i.e. only directly after
new
) and never as types (i.e. never as the type of a field, return type or parameter type of a method or type argument to a generic type, never cast to a class, never use it withinstanceof
). And as types, use only interfaces, not classes (and certainly not primitives in Java).That's what interfaces do: they enable object-oriented programming in Java and C#, without them, OOP would simply be impossible in those languages.