Better Software – Simpler, Faster
Design Patterns with modern C++
Prof. Peter Sommerlad HSR - Hochschule für Technik Rapperswil IFS Institute for Software Oberseestraße 10, CH-8640 Rapperswil [email protected] http://ifs.hsr.ch http://wiki.hsr.ch/PeterSommerlad
Sonntag, 19. April 2009 Peter Sommerlad [email protected]
• Work Areas o Refactoring Tools (C++,Groovy, Credo: Ruby, Python) for Eclipse o Decremental Development • People create Software (make SW 10% its size!) o communication o Modern Software Engineering o feedback o Patterns o courage Pattern-oriented Software Architecture (POSA) • Experience through Practice Security Patterns o programming is a trade • Background o Patterns encapsulate practical experience o Diplom-Informatiker (Univ. Frankfurt/M) • Pragmatic Programming o Siemens Corporate Research - o test-driven development Munich o automated development o itopia corporate information o Simplicity: fight complexity technology, Zurich (Partner) o Professor for Software HSR Rapperswil, Head Institute for Software © Prof. Peter Sommerlad 2
Sonntag, 19. April 2009 Goal
• Sure you can implement Design Patterns as shown in [GoF] in C++ o there are even old C++ code examples • But o standard C++ came after the book and especially templates, STL and std::tr1 (or boost) provide more means to apply the patterns (or some variation) • STL even implements some patterns o e.g. Iterator
© Prof. Peter Sommerlad 3
Sonntag, 19. April 2009 GoF Design Patterns
Creational Structural Behavioral
Abstract Factory Adapter Chain of Responsibility Prototype Bridge Command Singleton Composite Iterator Factory Method Decorator Mediator Builder Flyweight Memento Facade Observer Proxy State Strategy Visitor Template Method
object interactions composing objects
remove dependencies on concrete classes when creating objects
© Prof. Peter Sommerlad 4
Sonntag, 19. April 2009 Command [GoF]
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
© Prof. Peter Sommerlad 5
Sonntag, 19. April 2009 Command C++
• C function pointers are the most primitive Command implementation o but they lack state • C++ allows overloading the call operator and can thus implement Functor classes o instances are callable like functions but can have state • std::tr1 or boost define the function<> template to allow storage of arbitrary functor objects (with a given signature)
if you need more than separate execution the original command pattern might suit you better (>=2 methods) © Prof. Peter Sommerlad 6
Sonntag, 19. April 2009 Example code Command
• something silly, just for demo purposes o for more, see cute::test
#include
© Prof. Peter Sommerlad 7
Sonntag, 19. April 2009 Macro Command: bind+ vector
struct macroCommand:std::vector
© Prof. Peter Sommerlad 8
Sonntag, 19. April 2009 Dynamic Polymorphism vs. Policy-based Design • “classic” OO technique for variation would be to extract an interface and then provide different implementations of that interface • in C++ this means o run-time overhead of virtual member functions o object life-time issues of passed-in parameter objects (must live longer than using objects) • often polymorphism is not needed at run-time but only at compile time o when there is no need to vary behavior o e.g. for tests, for different platforms, for different usage
© Prof. Peter Sommerlad 9
Sonntag, 19. April 2009 Example: Dynamic Polymorphism
struct HelloTestImpl:HelloInterface { struct HelloInterface { std::ostringstream os; virtual void outputMessage() =0; void outputMessage() { virtual ~HelloInterface(){} os << "Hello World\n"; }; } }; struct HelloCoutImpl : HelloInterface { void thisIsATest() { void outputMessage() { HelloTestImpl forTest; std::cout << "Hello World\n"; HelloWorld doit(forTest); } doit(); }; ASSERT_EQUAL("Hello World\n",forTest.os.str()); } class HelloWorld { HelloInterface &hello; public: HelloWorld(HelloInterface& hello):hello(hello){} Variation for Test void operator()(){ // just to demo a functor... • hello.outputMessage(); } • Extracted Interface }; int main(){ • polymorphic call HelloCoutImpl toCout; HelloWorld doit(toCout); doit(); }
© Prof. Peter Sommerlad 10
Sonntag, 19. April 2009 Alternative PBD Static Polymorphism
struct HelloCoutImpl { static void outputMessage() { • Policy-based std::cout << "Hello World\n"; } Design }; template
© Prof. Peter Sommerlad 11
Sonntag, 19. April 2009 CRTP - curiously recurring template parameter • CRTP is when a class inherits from a template class that takes the derived class as template parameter:
Curious CuriousBase
template
class Curious : public CuriousBase
© Prof. Peter Sommerlad 12
Sonntag, 19. April 2009 Singleton (partially) different! • Don’t use Singleton: Parameterize from Above! Ensure a class only has one instance, and provide a global point of access to it. :-( ... 4. Permits a variable number of instances. The pattern makes it easy to change your mind and allow more than one instance of the Singleton class. Moreover, you can use the same approach to control the number of instances that the application uses. Only the operation that grants access to the Singleton instance needs to change. • but for the case given in the 4th consequence we can apply CRTP to count instances for all your classes that need to limit the number of instances o we throw an error if you try to instantiate more!
© Prof. Peter Sommerlad 13
Sonntag, 19. April 2009 CRTP limit object count for a class (usage/test) • ensure there can be only one one object or two
#include "LimitNofInstances.h" class one:LimitNofInstances
void testTwoInstances(){ two first; { two second; ASSERT_THROWS(two(),std::logic_error); } two nextsecond; ASSERT_THROWS(two(),std::logic_error); } © Prof. Peter Sommerlad 14
Sonntag, 19. April 2009 CRTP limit object count for a class (impl)
#include
© Prof. Peter Sommerlad 15
Sonntag, 19. April 2009 Null Object only implicitely in [GoF]
A Null Object provides a surrogate for another object that shares the same interface but does nothing. Thus, the Null Object encapsulates the implementation decisions of how to do nothing and hides those details from its collaborators Bobby Woolf in [PLoP3]
• requires shared interface and polymorphism struct HelloInterface { struct HelloNullImpl{ virtual void outputMessage() =0; static void outputMessage(){} virtual ~HelloInterface(){} }; }; template
© Prof. Peter Sommerlad static Polymorphism 16
Sonntag, 19. April 2009 Template Method
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
AbstractClass TemplateMethod(){ TemplateMethod() ... PrimitiveOperation1(); PrimitiveOperation1() ... PrimitiveOperation2() PrimitiveOperation2(); ... }
ConcreteClass PrimitiveOperation1() PrimitiveOperation2() run time configuration defines algorithm steps implementation © Prof. Peter Sommerlad 17
Sonntag, 19. April 2009 Template Method
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclassessuperclass redefine certain steps of an algorithm without changing the algorithm's structure.
ConcreteParam AbstractClass TemplateMethod(){ ... AbstractClass TemplateMethod() PrimitiveOperation1(); implicitely PrimitiveOperation1() TemplateMethod() ... defines PrimitiveOperation2() PrimitiveOperation2(); ... }
PrimitiveOperation1() PrimitiveOperation2()
ConcreteClass PrimitiveOperation1() ConcreteClass PrimitiveOperation2() PrimitiveOperation1() PrimitiveOperation2() compilerun time time configuration configuration defines defines algorithm algorithm steps steps implementation © Prof. Peter Sommerlad 17
Sonntag, 19. April 2009 Implementing static Template Method • write a template class that inherits from its template parameter • In this class implement the algorithm (Template Method) calling out to Super’s
methods class TMImpl{ protected: template
© Prof. Peter Sommerlad 18
Sonntag, 19. April 2009 template class cute::runner
template
© Prof. Peter Sommerlad 19 Sonntag, 19. April 2009 Null Object null_listener
struct null_listener{ // defines Contract of runner Null-Object Pattern parameter void begin(suite const &s, char const *info){} void end(suite const &s, char const *info){} void start(test const &t){} Template Method void success(test const &t,char const *msg){} Pattern void failure(test const &t,test_failure const &e){} Interface void error(test const &t,char const *what){} };
© Prof. Peter Sommerlad 20 Sonntag, 19. April 2009 Decorator
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Component Operation()
ConcreteC Decorator Operation() decoratedComp Operation()
Decorator::Operation(){ ... decoratedComp.Operation(); ConcreteD // do the decoration Operation() ... }
© Prof. Peter Sommerlad 21
Sonntag, 19. April 2009 Decorator
Attach additional responsibilities to an object staticallydynamically.. Decorators Decorators provide provide a flexible a flexible alternative alternative via tosubclassing subclassing for for extending extending functionality. functionality.
ConcreteParam Component Decorator Operation() implicitely Operation() defines
ConcreteC Decorator Operation() Operation() decoratedComp Operation()
Decorator::Operation(){ DecoratedComp ... Operation() DecoratedComp::Operation();decoratedComp.Operation(); ConcreteD // do the decoration Operation() ... }
© Prof. Peter Sommerlad 21
Sonntag, 19. April 2009 Decorator counting_listener
template
© Prof. Peter Sommerlad 22 Sonntag, 19. April 2009 What else?
• Have a look in Andrej’s book: o however, a bit of an overdose... o use the stuff from boost or std::tr1 instead of DIY
© Prof. Peter Sommerlad 23
Sonntag, 19. April 2009 Outlook: Adapter with Concept Maps • Concepts and concept maps provide “promising generic, non-intrusive, efficient, and identity preserving adapters.” [JMS07] • Example: Adapter for arrays to be used in the new for loop syntax with the For
Sonntag, 19. April 2009 Questions?
• Or contact me at [email protected]
© Prof. Peter Sommerlad 25
Sonntag, 19. April 2009 References
• [GoF] o Gamma E., Helm R., Johnson R., Vlissides J.: Design Patterns - Elements of reusable object-oriented Design, AW 1994 • [JMS07] o Jaakko Järvi, Matthew A. Marcus, and Jacob N. Smith. Library composition and adaptation using c++ concepts. In GPCE ’07: Proceedings of the 6th international conference on Generative programming and component engineering, pages 73–82, New York, NY, USA, 2007. ACM. • [VanJos] o David Vandervoorde, Nicolai Josuttis: C++ Templates: The Complete Guide • [PLoP3] o Martin R., Riehle D., Buschmann F.: Pattern Languages of Program Design 3, AW 1998
© Prof. Peter Sommerlad 26
Sonntag, 19. April 2009