A Property Container
is a class whose properties can be customized at runtime without having to edit your class definition.
This article has the only thorough example I could find. In it, they use the example of a customizable Movie class.
The PropertyContainer
base class provides methods to add/remove/retrieve properties stored in the class. Basically, it acts a lot like a HashMap
:
PropertyContainer:
+ addPropertyBy()
+ removeProperty()
+ getPropertyBy()
+ getPropertyKeys()
Then you have a Movie
class that inherits from the PropertyContainer
:
Movie extends PropertyContainer:
- rating
- available
- description
- title
- id
- price
+ [getters and setters for private properties]
Later, if you need to add releasedate
as a property to the Movie
class in one project, you have the ability to add it at runtime instead of updating your class.
Movie m = new Movie()
m.addPropertyBy("3/5/14", "releasedate")
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
In OOP we use polymorphism so an abstraction can have multiple implementations. Let's look at the following example:
A new requirement introduced and needs to bring in the acceleration perspective of the trains, so change the code as below.
The above code is not maintainable and lacks reusability (assuming we could reuse the acceleration mechanism for the same track platform). The following code applies the bridge pattern and separates the two different abstractions, train transport and acceleration.