This page last updated on: Mar. 31, 2002
The hierarchy of URL classes will be based on the Proxy design pattern. Proxy classes act as a 'stand-in' or surrogate for another type or object that has no built-in representation in the language. These Proxy classes will simplify the rules and functionality of real Web addresses, allowing easier URL handling in application code. Note that this assignment greatly simplifies URL rules, and is meant for assignment purposes only.
A design pattern named Factory Method will be used to provide a framework for URL Proxy object creation (Factory Method is also called Virtual Constructor). This framework allows new URL Proxy classes to be created and integrated into the overall application by simply deriving from two abstract base classes (the URL Proxy base class, and the URL Factory base class). Each URL Proxy concrete class will have a corresponding URL Factory concrete class responsible for creating instances. At run-time a virtual createInstance (or similarly named) function will be called on the URL Factory objects to decide which one is appropriate for creating the actual URL Proxy object. Something is needed to manage the collection of URL Factory objects, so for this assignment a URL Factory Mgr class will be defined. Since there should only be one instance of a URL Factory Mgr, this will be assured by using a design pattern named Singleton.
Inside the URL Proxy class hierarchy, a simplified Prototype design pattern will be implemented, using what is called a Clone function (Clone is also called Virtual Copy Constructor). The Clone function provides a way to create a copy (clone) of an object through a virtual function (C++ constructors are not allowed to be virtual).
In addition to these design techniques, the mutable keyword will be used in appropriate places, to illustrate the difference between logical constness and bit-wise constness.
For the Proxy classes, there are four common data elements stored in the UrlProxy base class:
The server host name is stored as lower case letters, for comparison with other URL Proxy objects.
For the derived Proxy classes, the following data elements will be present:
Provide output stream (display) operations for each Proxy class.
Provide a virtual copy constructor, named clone(), for each Proxy class.
Provide a function named openClientApp (or something named similarly) which in a real application would provide the capability of starting up the appropriate Internet client application with the appropriate parameters (i.e. Web browser with the Web address, FTP client with the server, port, path, e-mail client with the user and server). For this assignment, simply display a message indicating which client app is starting up, and display each data element separately.
Write a corresponding Factory class for each concrete URL Proxy class. For this assignment the only member function which needs to be implemented is the createInstance function (which takes the URL string and creates an appropriate Proxy object or returns a null pointer).
Use standard C++ library containers and iterators. In particular, if std::vector is used, use std::vector::iterator and std::vector::const_iterator instead of indexes.
In the main application, provide the following logic:
Provide error handling (at least a try and catch block in the main function, with one or more throw's at appropriate places). All heap objects should be delete'ed before the application exits, and there should be no possibility of application crashes due to memory corruption or bad logic. Otherwise simple error checks and displays are sufficient for any necessary error handling.
Namespaces are required, and all classes and constants and prototypes should be wrapped in a namespace.
Using boost::shared_ptr is recommended for easier memory management, although note that the boost::shared_ptr class does not automatically preserve the inheritance relationship between its internal pointers - i.e. FtpUrl* and HttpUrl* are related by inheritance, but boost::shared_ptr<FtpUrl> and boost::shared_ptr<HttpUrl> are not automatically related.
Name the source files urlmain.cpp, url.h and url.cpp, and optionally (if additional granularity is desired) ftpurl.h, ftpurl.cpp, httpurl.h, httpurl.cpp, mailurl.h, and mailurl.cpp.
virtual UrlProxy* clone () const = 0; // derived classes implement clone
HttpUrl* clone () const;
FtpUrl* clone () const { return new FtpUrl(*this); }
Note that the return type does not match in all three - this is a slight
relaxation of virtual function signature rules in the C++ standard (called
'covariant return type'). The return type can differ as long as the return
type is a derived type of the base virtual function return type (this is
a perfectly safe and typical usage of C++ derived types). Some compilers
do not support this yet, and workarounds will need to be put in place.
(For this assignment, the workaround is to always return a base pointer
- this will not lose any functionality.)
Make sure appropriate destructors are virtual.
Use the std::ifstream class to open and read the file - this allows the main extraction loop to be:
std::ifstream ifs(docName);
std::string tok;
while (ifs >> tok) {
// pass token to UrlFactoryMgr and create and push_back instance if appropriate
}
The main function, including try and catch blocks and blank lines for readability, can be easily written in 50 lines.
To add a new derived UrlProxy type, all that is needed is to write the new concrete classes, then add one line to the main function (register the UrlFactory with the singleton).
The boost library can be found at: http://www.boost.org/
Example design pattern C++ code can be found at: Patterns Code Examples
When parsing the input string in the derived UrlFactory::createInstance functions, the following std::string capabilities are useful: