--- trunk/tengDissertation/Appendix.tex 2006/06/07 19:51:57 2816 +++ trunk/tengDissertation/Appendix.tex 2006/06/08 15:44:14 2824 @@ -118,25 +118,165 @@ The Singleton pattern ensures that only one instance o OOPSE}. \subsection{\label{appendixSection:singleton}Singleton} -The Singleton pattern ensures that only one instance of a class is -created. All objects that use an instance of that class use the same -instance. +The Singleton pattern not only provides a mechanism to restrict +instantiation of a class to one object, but also provides a global +point of access to the object. Currently implemented as a global +variable, the logging utility which reports error and warning +messages to the console in {\sc OOPSE} is a good candidate for +applying the Singleton pattern to avoid the global namespace +pollution.Although the singleton pattern can be implemented in +various ways to account for different aspects of the software +designs, such as lifespan control \textit{etc}, we only use the +static data approach in {\sc OOPSE}. {\tt IntegratorFactory} class +is declared as +\begin{lstlisting}[float,caption={[A classic Singleton design pattern implementation(I)] Declaration of {\tt IntegratorFactory} class.},label={appendixScheme:singletonDeclaration}] + class IntegratorFactory { + public: + static IntegratorFactory* getInstance(); + protected: + IntegratorFactory(); + private: + static IntegratorFactory* instance_; + }; +\end{lstlisting} +The corresponding implementation is +\begin{lstlisting}[float,caption={[A classic implementation of Singleton design pattern (II)] Implementation of {\tt IntegratorFactory} class.},label={appendixScheme:singletonImplementation}] + +IntegratorFactory::instance_ = NULL; + +IntegratorFactory* getInstance() { + if (instance_ == NULL){ + instance_ = new IntegratorFactory; + } + return instance_; +} +\end{lstlisting} +Since constructor is declared as {\tt protected}, a client can not +instantiate {\tt IntegratorFactory} directly. Moreover, since the +member function {\tt getInstance} serves as the only entry of access +to {\tt IntegratorFactory}, this approach fulfills the basic +requirement, a single instance. Another consequence of this approach +is the automatic destruction since static data are destroyed upon +program termination. + \subsection{\label{appendixSection:factoryMethod}Factory Method} -The Factory Method pattern is a creational pattern which deals with -the problem of creating objects without specifying the exact class -of object that will be created. Factory Method solves this problem -by defining a separate method for creating the objects, which -subclasses can then override to specify the derived type of product -that will be created. +Categoried as a creational pattern, the Factory Method pattern deals +with the problem of creating objects without specifying the exact +class of object that will be created. Factory Method is typically +implemented by delegating the creation operation to the subclasses. + +Registers a creator with a type identifier. Looks up the type +identifier in the internal map. If it is found, it invokes the +corresponding creator for the type identifier and returns its +result. +\begin{lstlisting}[float,caption={[The implementation of Factory pattern (I)].},label={appendixScheme:factoryDeclaration}] + class IntegratorCreator; + class IntegratorFactory { + public: + typedef std::map CreatorMapType; + + bool registerIntegrator(IntegratorCreator* creator); + + Integrator* createIntegrator(const string& id, SimInfo* info); + + private: + CreatorMapType creatorMap_; + }; +\end{lstlisting} + +\begin{lstlisting}[float,caption={[The implementation of Factory pattern (II)].},label={appendixScheme:factoryDeclarationImplementation}] + bool IntegratorFactory::unregisterIntegrator(const string& id) { + return creatorMap_.erase(id) == 1; + } + + Integrator* + IntegratorFactory::createIntegrator(const string& id, SimInfo* info) { + CreatorMapType::iterator i = creatorMap_.find(id); + if (i != creatorMap_.end()) { + //invoke functor to create object + return (i->second)->create(info); + } else { + return NULL; + } + } +\end{lstlisting} + +\begin{lstlisting}[float,caption={[The implementation of Factory pattern (III)].},label={appendixScheme:integratorCreator}] + + class IntegratorCreator { + public: + IntegratorCreator(const string& ident) : ident_(ident) {} + + const string& getIdent() const { return ident_; } + + virtual Integrator* create(SimInfo* info) const = 0; + + private: + string ident_; + }; + + template + class IntegratorBuilder : public IntegratorCreator { + public: + IntegratorBuilder(const string& ident) : IntegratorCreator(ident) {} + virtual Integrator* create(SimInfo* info) const { + return new ConcreteIntegrator(info); + } + }; +\end{lstlisting} + \subsection{\label{appendixSection:visitorPattern}Visitor} + The purpose of the Visitor Pattern is to encapsulate an operation -that you want to perform on the elements of a data structure. In -this way, you can change the operation being performed on a -structure without the need of changing the classes of the elements -that you are operating on. +that you want to perform on the elements. The operation being +performed on a structure can be switched without changing the +interfaces of the elements. In other words, one can add virtual +functions into a set of classes without modifying their interfaces. +The UML class diagram of Visitor patten is shown in +Fig.~\ref{appendixFig:visitorUML}. {\tt Dump2XYZ} program in +Sec.~\ref{appendixSection:Dump2XYZ} uses Visitor pattern +extensively. +\begin{figure} +\centering +\includegraphics[width=\linewidth]{architecture.eps} +\caption[The architecture of {\sc OOPSE}] {Overview of the structure +of {\sc OOPSE}} \label{appendixFig:visitorUML} +\end{figure} + +\begin{lstlisting}[float,caption={[The implementation of Visitor pattern (I)]Source code of the visitor classes.},label={appendixScheme:visitor}] + class BaseVisitor{ + public: + virtual void visit(Atom* atom); + virtual void visit(DirectionalAtom* datom); + virtual void visit(RigidBody* rb); + }; +\end{lstlisting} + +\begin{lstlisting}[float,caption={[The implementation of Visitor pattern (II)]Source code of the element classes.},label={appendixScheme:element}] + class StuntDouble { + public: + virtual void accept(BaseVisitor* v) = 0; + }; + + class Atom: public StuntDouble { + public: + virtual void accept{BaseVisitor* v*} {v->visit(this);} + }; + + class DirectionalAtom: public Atom { + public: + virtual void accept{BaseVisitor* v*} {v->visit(this);} + }; + + class RigidBody: public StuntDouble { + public: + virtual void accept{BaseVisitor* v*} {v->visit(this);} + }; + +\end{lstlisting} \section{\label{appendixSection:concepts}Concepts} OOPSE manipulates both traditional atoms as well as some objects @@ -502,10 +642,10 @@ Dump2XYZ can transform an OOPSE dump file into a xyz f \subsection{\label{appendixSection:Dump2XYZ}Dump2XYZ} -Dump2XYZ can transform an OOPSE dump file into a xyz file which can -be opened by other molecular dynamics viewers such as Jmol and -VMD\cite{Humphrey1996}. The options available for Dump2XYZ are as -follows: +{\tt Dump2XYZ} can transform an OOPSE dump file into a xyz file +which can be opened by other molecular dynamics viewers such as Jmol +and VMD\cite{Humphrey1996}. The options available for Dump2XYZ are +as follows: \begin{longtable}[c]{|EFG|} @@ -536,7 +676,12 @@ The options available for Hydro are as follows: \end{longtable} \subsection{\label{appendixSection:hydrodynamics}Hydro} -The options available for Hydro are as follows: + +{\tt Hydro} can calculate resistance and diffusion tensors at the +center of resistance. Both tensors at the center of diffusion can +also be reported from the program, as well as the coordinates for +the beads which are used to approximate the arbitrary shapes. The +options available for Hydro are as follows: \begin{longtable}[c]{|EFG|} \caption{Hydrodynamics Command-line Options} \\ \hline