Design Patterns Elements of Reusable Object-Oriented Software by Erich Gamma