\documentclass[pdf,slideColor,colorBG,autumn]{prosper} \title{Design Patterns in KDE} \author{Marc Mutz} \institution{Bielefeld University} \date{23.\ April\ 2003} %\slideCaption{Design \begin{document} \maketitle \begin{slide}{Overview} \begin{itemize} \item What Design Patterns are \item What they are not \item Why would I want to use one? \item Case Study: The KDE DOM implementation. \item Other Examples of Design Pattern use in KDE and Qt \item Examples of Patterns not yet used in KDE and Qt \end{itemize} \end{slide} \begin{slide}{What Design Patterns are} Design Patterns are \begin{itemize} \item A higher-level language than the programming language to talk about software systems in, \item A set of general solutions to common problems in software engineering, \end{itemize} \begin{small} Def\/inition of \emph{Gamma et al}: ``Design Patterns are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.'' \end{small} \bigskip E.g., in \textbf{C}, \textbf{Inheritance} might be a \textbf{Design Pattern}, whereas in \textbf{C++}, it's built into the language. \end{slide} \begin{slide}{What Design Patterns are not} Design Patterns are not \begin{itemize} \item Algorithms such as QuickSort or Boyer-Moore. \item Language features, such as polymorphism or exceptions. \item Implementation patterns, such as the \textbf{d-pointer} or the \textbf{virtual\_hook}. \item Software components such as toolkits and frameworks \end{itemize} \end{slide} \begin{slide}{Why would I want to use one?} \begin{small} Short answer: Because it makes you a better programmer. \bigskip Long answer: On learning Design Patterns, you will f\/ind that you have known and implemented at least some of the patterns already. \medskip You may have copied code or ideas, or you might have solved the problem yourself. \medskip What you more often than not have \textbf{not} done is think of the solution as a pattern to \textbf{re-apply} whenever a similar problem arises again. \medskip And almost certainly, you haven't \textbf{named} them and put them in a catalog to refer to for \textbf{inspiration} and discussions about design. \end{small} \end{slide} \part{A Case Study: KDE's DOM Implementation} \begin{slide}{Case Study: DOM: Factory Method} \texttt{DOM::Document} implements the \textbf{Factory Method} pattern:\\[1em] \begin{scriptsize} \texttt{% \textbf{class} Document : \textbf{public} Node \{\\ \ // ...\\ \ // All of these are Factory Methods:\\ \ Element createElement(...); \\ \ Attr createAttribute(...);\\ \ Event createEvent(...);\\ \ // ...\\ \}; } \end{scriptsize}\\[0.5em] \textbf{Factory Methods} abstract away the creation of objects. This is essential if you want to hide the implementation and only want to export the interface. \end{slide} \begin{slide}{Case Study: DOM: Bridge} Almost all DOM classes implement the \textbf{Bridge} pattern (a.k.a.\ Handle): \begin{itemize} \item \texttt{Node} (the \textbf{Abstractor}) contains a member of type \texttt{NodeImpl} (the \textbf{Implementor}) \item \texttt{Element} (the \textbf{Ref\/ined Abstractor}) inherits Node \end{itemize} \bigskip This pattern is \textbf{not a d-pointer}: \begin{itemize} \item d-pointer involves a dumb Data Object with no behavior. \item Implementor is stand-alone (contains all data and behavior). \end{itemize} \end{slide} \begin{slide}{Case Study: DOM: Composite} The \texttt{Node}-derived DOM classes implement the \textbf{Composite} pattern: For a basic interface (\texttt{Node}), there are two classes of implementations: \begin{itemize} \item \textbf{Leaves} (\texttt{Text}, \texttt{Comment}) that contain no further children. \item \textbf{Composites} (\texttt{Element}, \texttt{Attr}) that may have one or more children. \end{itemize} The important aspect of this pattern is that container classes here implement the interface of the objects they contain. \end{slide} \begin{slide}{DOM: Chain of Responsibility} \texttt{Event}, together with \texttt{NodeImpl::dispatchEvent()} implements a variant of the \textbf{Chain of Responsibility} pattern: \begin{itemize} \item \textbf{Handler} (\texttt{Node}) objects hold references to other Handlers, thus forming an object chain. \item A \texttt{handleRequest()} method on Handler either handles the request or passes it on to the next Handler in the chain. \end{itemize} Typically, \textbf{Handler} will be an interface so that the class of each Handler in the chain can be different. This is not the \textbf{Chain of Responsibility} as the book says, but similar enough. \end{slide} \begin{slide}{Case Study: DOM: Observer} The \texttt{EventListener} class implements the \textbf{Observer} pattern: \begin{itemize} \item A \textbf{Subject} (\texttt{Node}) registers \textbf{Observers} (\texttt{EventListener}) \item On state change, Subject calls Observer's single method, in this case \texttt{handleEvent(Event\&)} \end{itemize} You'll f\/ind few Observers in KDE, since Qt's \textbf{signal/slot} mechanism reduces the need for this pattern. Subjects know their type, so Observers can also be \textbf{Visitors}. \end{slide} \part{Other Examples of Design Pattern Use in KDE/Qt} \begin{slide}{Design Patterns Use: Factories} Both \textbf{Abstract Factory} and \textbf{Factory Method} are implemented in \texttt{QTextCodec}: \bigskip \begin{small} \texttt{% \textbf{class} QTextCodec \{\\ \ // ...\\ \ \textbf{static} QTextCodec *\\ \ \ \ codecForName( \textbf{const char} * name, ... );\\ \ // ...\\ \ \textbf{virtual} QTextDecoder * makeDecoder() \textbf{const};\\ \ \textbf{virtual} QTextEncoder * makeEncoder() \textbf{const};\\ \ // ...\\ \}; } \end{small} \end{slide} \begin{slide}{KDE/Qt Design Pattern Use: Builder} \texttt{KSieve::Parser} implements the \textbf{Builder} pattern: Instead of constructing an explicit parse tree, it calls methods in the \texttt{KSieve::ScriptBuilder} interface:\\[2em] \begin{tiny}% \texttt{% \textbf{class} ScriptBuilder \{\\ \ // ...\\ \ \textbf{virtual void} commandStart( \textbf{const} QString \& identifier ) = 0;\\ \ \textbf{virtual void} commandEnd() = 0;\\ \ \textbf{virtual void} taggedArgument( \textbf{const} QString \& tag ) = 0;\\ \ \textbf{virtual void} stringArgument( \textbf{const} QString \& str, {...} ) = 0;\\ \ \textbf{virtual void} numberArgument( \textbf{unsigned long} number ) = 0;\\ \ // ...\\ \};% }% \end{tiny} \end{slide} \begin{slide}{Design Pattern Use: Builder II} Implementations of this interface can reuse the parser to do totally different things, such as \textbf{pretty-printing} the script, creating a DOM-like \textbf{object tree}, \textbf{test} the parser\ldots\\[1.5em] \begin{tiny}% \texttt{% \textbf{class} PrettyPrintingScriptBuilder \{\\ \ // ...\\ \ \textbf{void} commandStart( \textbf{const} QString \& id ) \{\\ \ \ \ mStream <\/< QString().fill( ' ', mIndent ) <\/< id;\\ \ \}\\ \ \textbf{void} commandEnd() \{ mStream <\/< endl; \}\\ \ \textbf{void} numberArgument( \textbf{unsigned long} num ) \{ mStream <\/< num; \}\\ \ // ...\\% \textbf{private}:\\ \ QTextStream mStream;\\ \ \textbf{int} mIndent;\\ \};% }% \end{tiny} \end{slide} \begin{slide}{Design Pattern Use: Decorator} \texttt{QFrame} implements the \textbf{Decorator} pattern: \begin{itemize} \item \texttt{QFrame}: \emph{Is} a \texttt{QWidget}, \emph{decorates} one with a border. \item \texttt{QScrollView}: \emph{Is} a \texttt{QWidget}, \emph{decorates} one with scrollbar(s). \end{itemize} The pattern here is: \begin{itemize} \item Basic interface (\texttt{QWidget}) \item Concrete implementations (\texttt{QPushButton}, etc) \item Decorator implementations that contain a member of basic type, which they decorate with additional state or functionality. \end{itemize} \end{slide} \begin{slide}{Design Pattern Use: Strategy} There are two examples of \textbf{Strategy} implementations in KMail: \begin{description} \item[AttachmentStrategy] Encapsulates an algorithm to decide which attachments to display. \item[HeaderStrategy] Encapsulates an algorithm to decide which header f\/ields to display. \end{description} The pattern here is: \begin{itemize} \item Base interface (\texttt{AttachmentStrategy}) \item Concrete implementations (\texttt{\{Iconic,Smart,\ldots\}AttachmentStrategy}). \item Context class that refers to a member of the abstract type to perform tasks. \end{itemize} \end{slide} \begin{slide}{Design Pattern Use: Strategy II} \begin{tiny} \texttt{% \textbf{class} AttachmentStrategy \{\\ \ \textbf{virtual bool} inlineNestedMessages() \textbf{const} = 0;\\ \};\\ \textbf{class} IconicAttachmentStrategy :\ \textbf{public} AttachmentStrategy \{\\ \ \textbf{bool} inlineNestedMessages() \textbf{const} \{ \textbf{return false}; \}\\ \};\\ \textbf{class} SmartAttachmentStrategy :\ \textbf{public} AttachmentStrategy \{\\ \ \textbf{bool} inlineNestedMessages() \textbf{const} \{ \textbf{return true}; \}\\ \};\\ \textbf{class} ObjectTreeParser \{\\ \ \textbf{bool} processMessageRfc822Subtype(...) \{\\ \ \ \ // ...\\ \ \ \ if ( mAttachmentStrategy->inlineNestedMessages() ) \{\\ \ \ \ \ \ // expand the message\\ \ \ \ \} else \{\\ \ \ \ \ \ // make an icon instead\\ \ \ \ \}\\ \ \};\\ \};\\ } \end{tiny} \end{slide} \part{The Rest} \begin{slide}{Patterns not yet used in KDE} I promised to explain the \textbf{Null Object} pattern. You all know code that looks like this:\\[1em] \texttt{% if ( mFoo )\\ \ \ mFoo->doSomething();\\ else\\ \ \ doSomethingWithoutFoo();% }\\[1em] If your implementation is cluttered with this type of code, and \texttt{mFoo} is \textbf{State} or \textbf{Strategy}-like, you can \textbf{refactor} to make the code use the \textbf{Null Object} pattern: \end{slide} \begin{slide}{Refactoring: Introduce Null Object} \texttt{% if ( mFoo )\\ \ \ mFoo->doSomething();\\ else\\ \ \ doSomethingWithoutFoo();% }\\[1em] \begin{enumerate} \item Implement \texttt{mFoo}'s interface in a \texttt{NullFoo} class, where each method's implementation consists of the \texttt{else} leg of conditionals like the above. \item Instead of setting \texttt{mFoo} to null to indicate it's absence, put a reference to a \texttt{NullFoo} instance there. \item Remove the conditionals. \end{enumerate} \end{slide} \begin{slide}{How to get there?} \begin{center} You've just seen one application of a technique called \textbf{Refactoring} \bigskip\bigskip \begin{large} This is supposed to be a slide on refactoring, but that is for another talk, at another conference. ;-) \end{large} \bigskip\bigskip \bigskip\bigskip \bigskip\bigskip (or get your hands on the Book(s)) \end{center} \end{slide} \end{document}