Sunday, October 26, 2014

Facade design pattern implementation in C++



Facade means the exterior of any object in general. Facade Design Pattern provides similar functionality as well. It provides a simple interface to a complex system. Just as we can not tell from the exterior of a building what lies inside it, Facade design pattern provides an interface which hides the internal complexity of a system. It only exposes the desired interfaces which have to be used by a client. It can be only a small subsystem of the complex system as the client may not need all the functionality of the complex system. Also it could modify the interfaces as well to provide the complete functionality of the system.

Facade Design Pattern
Facade Design Pattern

 For our implementation of the Facade Design Pattern, we have chosen example of Online Shopping model. The following diagram represents the relationships and flow between the classes.

Class Diagram for below example
The example works like this. OnlineShoppingFacade is the interface which is exposed to the customers (us). It's just like any portal like Flipkart, Amazon or eBay. Now we do not know what the heck is going behind those websites. All we know is that we have just placed an order and we will get a delivery after a certain period of time. Of course there is a status tracker something like this




But still the intricacies behind the process is hidden away from us. This is the Facade for the Online Shopping Portal.

Below is a simplistic implementation just to demo how Facade Design Pattern works using a C++ example.

Facade Design Pattern Implementation(C++)

Update(5th Nov 2014): The code is updated to work on linux platform as well.



#include <iostream>
#include <string>
#ifdef _WIN32
#include <windows.h>
#elif defined __linux__
#include <unistd.h>
#endif

/* Uncomment below line to enable debug logs */
/* #define DEBUG */
 
std::string _stateToStrCourier[]   = { "Received", "VerifyReachbility", "AssignPerson", 
                                       "DispatchPackage", "GetDeliveryConfirmation", "Complete"};
std::string _stateToStrVendor[]    = { "Received", "VerifyInventory", "GetItemFromWareHouse", 
                                       "PackItem", "ContactCourier", "Complete"};
std::string _stateToStrOrderTeam[] = { "Received", "VerifyPayment", "ContactVendor", "Complete"};

void mySleep(unsigned int millisecs)
{
#ifdef _WIN32
 Sleep(millisecs);
#elif defined __linux__
 usleep(1000 * millisecs);
#endif
}

class Courier
{
public:
 void submitRequestToCourier()
 {
  _state = 0;
 }
 bool checkStatus()
 {
#ifdef DEBUG
  std::cout<<"Courier: Current State: "<<_stateToStrCourier[_state]<< std::endl;
#endif
  mySleep(500); /* Do some useful work here */

  _state++;
  if (_state == Complete)
   return 1;
  return 0;
 }
private:
 enum States
 {
  Received, VerifyReachbility, AssignPerson, DispatchPackage, GetDeliveryConfirmation, Complete
 };
 int _state;
};
 
class Vendor
{
public:
 void submitRequestToVendor()
 {
  _state = 0;
 }
 bool checkStatus()
 {
#ifdef DEBUG
  std::cout<<"Vendor: Current State: "<<_stateToStrVendor[_state]<< std::endl;
#endif
  mySleep(500); /* Do some useful work here */

  _state++;
  if (_state == Complete)
   return 1;
  return 0;
 }
private:
 enum States
 {
  Received, VerifyInventory, GetItemFromWareHouse, PackItem, ContactCourier, Complete
 };
 int _state;
 
};
 
class OrderingTeam
{
public:
 void submitRequestToOrderTeam()
 {
  _state = 0;
 }
 bool checkStatus()
 {
#ifdef DEBUG
  std::cout<<"OrderingTeam: Current State: "<<_stateToStrOrderTeam[_state]<< std::endl;
#endif
  mySleep(500); /* Do some useful work here */ 
  _state++;
  if (_state == Complete)
   return 1;
  return 0;
 }
private:
 enum States
 {
  Received, VerifyPayment, ContactVendor, Complete
 };
 int _state;
};
 
class OnlineShoppingFacade
{
public:
 OnlineShoppingFacade()
 {
  _count = 0;
 }
 void submitRequest()
 {
  _state = 0;
 }
 bool checkStatus()
 {
  /* Item request has just been received */
  switch(_state)
  {
  case Received:
   _state++;
   /* Forward the job request to the ordering team */
   _order.submitRequestToOrderTeam();
   std::cout << "submitted to Order Team - " << _count <<
    " followups till now" << std::endl;
   break;
  case SubmittedToOrderTeam:
   /* If order team has completed verification, 
   place the request with vendor */
   if (_order.checkStatus())
   {
    _state++;
    _vendor.submitRequestToVendor();
    std::cout << "submitted to Vendor - " << _count <<
     " followups till now" << std::endl;
   }
   break;
  case SubmittedToVendor:
   /* If vendor has packed the item, forward it to courier */
   if (_vendor.checkStatus())
   {
    _state++;
    _courier.submitRequestToCourier();
    std::cout << "submitted to Courier - " << _count <<
     " followups till now" << std::endl;
   }
   break;
  case SubmittedToCourier:
   /* If package is delivered, order is complete */
   if (_courier.checkStatus())
    return 1;
  default:
   break;
  }
 
  _count++;
 
  /* The order is not complete */
  return 0;
 }
 int numFUPs()
 
 {
  return _count;
 }
private:
 enum States
 {
  Received, SubmittedToOrderTeam, SubmittedToVendor, SubmittedToCourier
 };
 
 int _state;
 int _count;
 
 OrderingTeam _order;
 Vendor _vendor;
 Courier _courier;
};
 
int main()
{
 OnlineShoppingFacade onlinereq;
 
 onlinereq.submitRequest();
 
 /* Keep checking until order is complete */
 while (!onlinereq.checkStatus());
 
 std::cout << "Order completed after " << onlinereq.numFUPs() << 
  " followups" << std::endl;
}


Saturday, October 18, 2014

Create a SOAP web service client in C++

What is SOAP?

SOAP(Simple Object Access Protocol) is a great way to exchange information over the network. Normally it is used with application protocols like HTTP, SMTP etc. The envelope containing the information is XML based.

It provides the basic messaging infrastructure for web services. 

An example SOAP request looks like :


 
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header>
    <ns1:RequestHeader
         soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next"
         soapenv:mustUnderstand="0"
         xmlns:ns1="https://www.google.com/apis/ads/publisher/v201403">
      <ns1:networkCode>123456</ns1:networkCode>
      <ns1:applicationName>DfpApi-Java-2.1.0-dfp_test</ns1:applicationName>
    </ns1:RequestHeader>
  </soapenv:Header>
  <soapenv:Body>
    <getAdUnitsByStatement xmlns="https://www.google.com/apis/ads/publisher/v201403">
      <filterStatement>
        <query>WHERE parentId IS NULL LIMIT 500</query>
      </filterStatement>
    </getAdUnitsByStatement>
  </soapenv:Body>
</soapenv:Envelope>

The corresponding response would look like :
 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <ResponseHeader xmlns="https://www.google.com/apis/ads/publisher/v201403">
      <requestId>xxxxxxxxxxxxxxxxxxxx</requestId>
      <responseTime>1063</responseTime>
    </ResponseHeader>
  </soap:Header>
  <soap:Body>
    <getAdUnitsByStatementResponse xmlns="https://www.google.com/apis/ads/publisher/v201403">
      <rval>
        <totalResultSetSize>1</totalResultSetSize>
        <startIndex>0</startIndex>
        <results>
          <id>2372</id>
          <name>RootAdUnit</name>
          <description></description>
          <targetWindow>TOP</targetWindow>
          <status>ACTIVE</status>
          <adUnitCode>1002372</adUnitCode>
          <inheritedAdSenseSettings>
            <value>
              <adSenseEnabled>true</adSenseEnabled>
              <borderColor>FFFFFF</borderColor>
              <titleColor>0000FF</titleColor>
              <backgroundColor>FFFFFF</backgroundColor>
              <textColor>000000</textColor>
              <urlColor>008000</urlColor>
              <adType>TEXT_AND_IMAGE</adType>
              <borderStyle>DEFAULT</borderStyle>
              <fontFamily>DEFAULT</fontFamily>
              <fontSize>DEFAULT</fontSize>
            </value>
          </inheritedAdSenseSettings>
        </results>
      </rval>
    </getAdUnitsByStatementResponse>
  </soap:Body>
</soap:Envelope>
Courtesy : https://developers.google.com/doubleclick-publishers/docs/soap_xml

The above is an example of Google's web service which provides Ad Units to the requester based on some filters.

Web Services provide an easy platform independent way to exchange information over the network.
The following picture shows the basic flow on how the Service Provider caters the request of the consumer.

                                                                           Source: http://www.service-architecture.com
Following is an implementation of a SOAP client in C++ which calls the Web Service to get the stock quotes based on a symbol(company ticker).

The example uses gSoap library for SOAP encoding/decoding and Xerces library to extract the data from the SOAP response (XML).

I have used the web service URL http://www.webservicex.net/stockquote.asmx?WSDL

Resources:

  1. gSOAP library (2.8.18) http://sourceforge.net/projects/gsoap2/files/
  2. Xerces library (3.1.1) http://xerces.apache.org/mirrors.cgi#binary
Setup for Visual Studio 2005:
  1. Unzip gSOAP library at any location (Lets say C:\tools , so the location will be C:\gsoap-2.8)
  2. Download only the binary distribution of xerces xerces-c-3.1.1-x86-windows-vc-8.0.zip
  3. Unzip the zip file at C:\  so that location becomes C:\xerces-c-3.1.1-x86-windows-vc-8.0
  4. Create an empty Win32 Console Application project.
  5. Add theses paths to the Additional Include Directories :
    "C:\xerces-c-3.1.1-x86-windows-vc-8.0\include";"C:\gsoap-2.8\gsoap\";"C:\gsoap-2.8\gsoap\import"

  6. Add these paths to Additional Library Directories :
    "C:\xerces-c-3.1.1-x86-windows-vc-8.0\lib"

  7. Add these libs to the dependency list:


    Notice that since we are using a Debug configuration here, we added xerces-c_3D.lib. For Release configuration, use xerces-c_3.lib
  8. Add this location to your environment Path variable C:\xerces-c-3.1.1-x86-windows-vc-8.0\bin or copy the xerces dlls (xerces-c_3_1.dll and xerces-c_3_1D.dll) into the output path of the project(i.e. same path where the exe of the project will be created). These will be present at the location C:\xerces-c-3.1.1-x86-windows-vc-8.0\bin
  9. Open a command prompt and go to gSOAP win32 bin directory and run following commands :

    wsdl2h.exe -o quote.h http://www.webservicex.net/stockquote.asmx?WSDL


    This will generate quote.h which contains class definitions for the web service.
    soapcpp2.exe /IC:\tools\gsoap_2.8.18\gsoap-2.8\gsoap\import quote.h
    This generates following files :

    StockQuoteSoap.GetQuote.req.xml
    StockQuoteSoap.GetQuote.res.xml
    StockQuoteSoap.nsmap
    soapC.cpp
    soapClient.cpp
    soapClientLib.cpp
    soapH.h
    soapServer.cpp
    soapServerLib.cpp
    soapStub.h
  10. Now add these generated files to the Visual Studio project created earlier :
    soapH.h , 
    soapC.cpp, soapClient.cpp, soapStub.h, quote.h

    Also these add two additional files from C:\tools\gsoap_2.8.18\gsoap-2.8\gsoap to your project:
    stdsoap2.cpp, stdsoap2.h
  11. Now its time to create some files on our own :).  Create these files in the project and copy the contents from the code below :

    quote.cpp, parser.hpp, stock.hpp
  12. SOAP Web Service client implementation(c++)

    
    //quote.cpp
    #include "soapH.h"    // include the generated proxy
    #include <xercesc/sax/HandlerBase.hpp>
    #include <xercesc/util/XMLString.hpp>
    #include <xercesc/framework/MemBufInputSource.hpp>
    #include <xercesc/util/OutOfMemoryException.hpp>
    #include <xercesc/dom/DOM.hpp>
    #include <xercesc/dom/DOMDocument.hpp>
    #include <xercesc/dom/DOMDocumentType.hpp>
    #include <xercesc/dom/DOMElement.hpp>
    #include <xercesc/dom/DOMImplementation.hpp>
    #include <xercesc/dom/DOMImplementationLS.hpp>
    #include <xercesc/dom/DOMNodeIterator.hpp>
    #include <xercesc/dom/DOMNodeList.hpp>
    #include <xercesc/dom/DOMText.hpp>
    #include <xercesc/parsers/XercesDOMParser.hpp>
    #include <xercesc/util/XMLUni.hpp>
    #include "parser.hpp"
    
    XERCES_CPP_NAMESPACE_USE
    
    GetXml::GetXml()
    {
     try
     {
      XMLPlatformUtils::Initialize();  // Initialize Xerces infrastructure
     }
     catch( XMLException& e )
     {
      char* message = XMLString::transcode( e.getMessage() );
      std::cout << "XML toolkit initialization error: " << message << std::endl;
      XMLString::release( &message );
     }
    
     // Tags and attributes used in XML file.
     // Can't call transcode till after Xerces Initialize()
     TAG_root  = XMLString::transcode("StockQuotes");
     TAG_Stock = XMLString::transcode("Stock");
     TAG_Symbol = XMLString::transcode("Symbol");
     TAG_Last = XMLString::transcode("Last");
     TAG_Date = XMLString::transcode("Date");
     TAG_Time = XMLString::transcode("Time");
     TAG_Change = XMLString::transcode("Change");
     TAG_Open = XMLString::transcode("Open");
     TAG_High = XMLString::transcode("High");
     TAG_Low = XMLString::transcode("Low");
     TAG_Volume = XMLString::transcode("Volume");
     TAG_MktCap = XMLString::transcode("MktCap");
     TAG_PrevClose = XMLString::transcode("PreviousClose");
     TAG_PercentChange = XMLString::transcode("PercentageChange");
     TAG_AnnRange = XMLString::transcode("AnnRange");
     TAG_Earns = XMLString::transcode("Earns");
     TAG_PE = XMLString::transcode("P-E");
     TAG_Name = XMLString::transcode("Name");
     
     m_XmlParser = new XercesDOMParser;
     m_Stock = new Stock;
    }
    
    GetXml::~GetXml()
    {
     // Free memory
     delete m_XmlParser;
     delete m_Stock;
    
     try
     {
      XMLString::release( &TAG_root );
     }
     catch( ... )
     {
      std::cout << "Unknown exception encountered in Destructor" << std::endl;
     }
    
     // Terminate Xerces
     try
     {
      XMLPlatformUtils::Terminate();  // Terminate after release of memory
     }
     catch( xercesc::XMLException& e )
     {
      char* message = xercesc::XMLString::transcode( e.getMessage() );
    
      std::cout << "XML toolkit teardown error: " << message << std::endl;
      XMLString::release( &message );
     }
    }
    
    void GetXml::readXml(std::string& xmlStr)
    throw( std::runtime_error )
    {
     // Configure DOM parser.
     m_XmlParser->setValidationScheme( XercesDOMParser::Val_Never );
     m_XmlParser->setDoNamespaces( false );
     m_XmlParser->setDoSchema( false );
     m_XmlParser->setLoadExternalDTD( false );
    
     try
     {
      xercesc_3_1::MemBufInputSource xmlBuf((const XMLByte*)xmlStr.c_str(), xmlStr.size(),
       "xmlBuf (in memory)");
      m_XmlParser->parse( xmlBuf );
    
      xercesc_3_1::DOMDocument* xmlDoc = m_XmlParser->getDocument();
    
      DOMElement* elementRoot = xmlDoc->getDocumentElement();
      if( !elementRoot ) throw(std::runtime_error( "Empty XML document" ));
    
      DOMNodeList*      children = elementRoot->getChildNodes();
      const  XMLSize_t nodeCount = children->getLength();
    
      // For all nodes, children of "StockQuotes" in the XML tree.
    
      for( XMLSize_t xx = 0; xx < nodeCount; ++xx )
      {
       DOMNode* currentNode = children->item(xx);
       if( currentNode->getNodeType() &&  // true is not NULL
        currentNode->getNodeType() == DOMNode::ELEMENT_NODE ) // is element 
       {
        // Found node which is an Element. Re-cast node as element
        DOMElement* currentElement
         = dynamic_cast< xercesc::DOMElement* >( currentNode );
        if( XMLString::equals(currentElement->getTagName(), TAG_Stock))
        {
         DOMNodeList*      children1 = currentElement->getChildNodes();
         const  XMLSize_t nodeCount1 = children1->getLength();
         for( XMLSize_t yy = 0; yy < nodeCount1; ++yy )
         {
          DOMNode* currentNode1 = children1->item(yy);
          if( currentNode1->getNodeType() &&  // true is not NULL
           currentNode1->getNodeType() == DOMNode::ELEMENT_NODE ) // is element 
          {
           // Found node which is an Element. Re-cast node as element
           DOMElement* currentElement1
            = dynamic_cast< xercesc::DOMElement* >( currentNode1 );
           std::cout<<XMLString::transcode(currentElement1->getTagName())<<": "
            <<XMLString::transcode(currentElement1->getTextContent())<<std::endl;
    
           std::string sym(XMLString::transcode(currentElement1->getTextContent()));
    
           if(XMLString::equals(currentElement1->getTagName(), TAG_Symbol))
           {
            m_Stock->SetSymbol(sym);
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Last))
           {
            m_Stock->SetLast(sym);
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Date))
           {
            m_Stock->SetDate(sym);
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Time))
           {
            m_Stock->SetTime(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Change))
           {
            m_Stock->SetChange(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Open))
           {
            m_Stock->SetOpen(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_High))
           {
            m_Stock->SetHigh(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Low))
           {
            m_Stock->SetLow(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Volume))
           {
            m_Stock->SetVolume(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_MktCap))
           {
            m_Stock->SetMktCap(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_PrevClose))
           {
            m_Stock->SetPrevClose(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_PercentChange))
           {
            m_Stock->SetPercentChange(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_AnnRange))
           {
            m_Stock->SetAnnRange(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Earns))
           {
            m_Stock->SetEarns(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_PE))
           {
            m_Stock->SetPE(sym);
    
           }
           else if(XMLString::equals(currentElement1->getTagName(), TAG_Name))
           {
            m_Stock->SetName(sym);
           }
          }
         }
        }
       }
      }
    
      std::cout<<m_Stock->ToString();
     }
     catch( xercesc::XMLException& e )
     {
      char* message = xercesc::XMLString::transcode( e.getMessage() );
      std::ostringstream errBuf;
      errBuf << "Error parsing file: " << message << std::flush;
      XMLString::release( &message );
     }
    }
    
    int main(int argc, char** argv){
     struct soap *soap = soap_new(); 
     struct _ns1__GetQuote sym;
     struct _ns1__GetQuoteResponse quote;
     GetXml xml;
     std::string response="";
     std::string str(argv[1]);
     sym.symbol = &str;
    
     soap_init(soap);
    
     //Call the web service
     if (soap_call___ns1__GetQuote(soap, NULL, NULL, &sym, quote) == SOAP_OK) {
      //std::cout<<"Symbol: "<<*(sym.symbol)<<std::endl<<" Quote: "<<*(quote.GetQuoteResult)<<std::endl;
      response = *(quote.GetQuoteResult);
      free (quote.GetQuoteResult);
     }
     else {
      std::cout<<"Error in execution of GetQuote:: "<<soap->buf<<std::endl;
      return(0);
     }
    
     //Parse the SOAP response 
     xml.readXml(response);
     return 0;
    }
    
    // Copied from StockQuoteSoap.nsmap file
    SOAP_NMAC struct Namespace namespaces[] =
    {
     {"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},
     {"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},
     {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},
     {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},
     {"ns1", "http://www.webserviceX.NET/", NULL, NULL},
     {NULL, NULL, NULL, NULL}
    };
    
    



    
    //stock.hpp
    #include <sstream>
    class Stock
    {
     std::string symbol_;
     std::string last_;
     std::string date_;
     std::string time_;
     std::string change_;
     std::string open_;
     std::string high_;
     std::string low_;
     std::string volume_;
     std::string mktcap_;
     std::string previousclose_;
     std::string percentagechange_;
     std::string annrange_;
     std::string earns_;
     std::string p_e_;
     std::string name_;
    
    public:
     Stock() {}
     Stock(std::string symbol) {symbol_ = symbol;}
    
     void SetSymbol(std::string symbol) {symbol_ = symbol;}
     void SetLast(std::string last) {last_ = last;}
     void SetDate(std::string date) {date_ = date;}
     void SetTime(std::string time) {time_ = time;}
     void SetChange(std::string change) {change_ = change;}
     void SetOpen(std::string open) {open_ = open;}
     void SetHigh(std::string high) {high_ = high;}
     void SetLow(std::string low) {low_ = low;}
     void SetVolume(std::string volume) {volume_ = volume;}
     void SetMktCap(std::string mktcap) {mktcap_ = mktcap;}
     void SetPrevClose(std::string previousclose) {previousclose_ = previousclose;}
     void SetPercentChange(std::string percentagechange) {percentagechange_ = percentagechange;}
     void SetAnnRange(std::string annrange) {annrange_ = annrange;}
     void SetEarns(std::string earns) {earns_ = earns;}
     void SetPE(std::string p_e) {p_e_ = p_e;}
     void SetName(std::string name) {name_ = name;}
    
     //ToString function overridden to display in short format  
     std::string ToString() const
     {
      std::stringstream sstr;
      sstr << "\'" << symbol_ << "\' Open: " << open_
       << ", Last: " << last_;
      return sstr.str();
     }
    };
    
    



    
    //parser.hpp
    #include "stock.hpp"
    class GetXml
    {
    public:
     GetXml();
     ~GetXml();
    
     //Function to read the XML string
     void readXml(std::string&) throw(std::runtime_error);
    
    
    private:
     xercesc_3_1::XercesDOMParser *m_XmlParser; //DOM Parser pointer
     Stock *m_Stock;        //To save the returned data
    
     XMLCh* TAG_root;
     XMLCh* TAG_Stock;
     XMLCh* TAG_Symbol;
     XMLCh* TAG_Last;
     XMLCh* TAG_Date;
     XMLCh* TAG_Time;
     XMLCh* TAG_Change;
     XMLCh* TAG_Open;
     XMLCh* TAG_High;
     XMLCh* TAG_Low;
     XMLCh* TAG_Volume;
     XMLCh* TAG_MktCap;
     XMLCh* TAG_PrevClose;
     XMLCh* TAG_PercentChange;
     XMLCh* TAG_AnnRange;
     XMLCh* TAG_Earns;
     XMLCh* TAG_PE;
     XMLCh* TAG_Name;
    };
    
    


  13. Now the project is ready to compile. Use F7 to compile the solution.
  14. After the binary is generated, run it like this :
    <binary-name>.exe<space><Ticker-Name>

    e.g. If project name was soap
    soap.exe GOOG
  15. This program is specific to the Stock Quote web service provided by http://www.webservicex.net/ . This program can be modified to use any web service. Depending upon the expected SOAP response, the result can be parsed accordingly. Then following files will be modified :

    stock.hpp - Class which stores the data from SOAP response
    parser.hpp - Class which parses the XML result from SOAP response

Wednesday, April 2, 2014

Builder Design Pattern Implementation in C++


Sometimes an application gets too complicated and developing it becomes a pain. These applications contain complex objects which are made up from other objects from different classes. Now these objects may vary. So there has to be a process of building the complex objects so that there is scope of building different products using the same process.

That is when a creational design pattern called Builder comes into picture. It separates the details of construction process from its representation

Now what in the world that line means actually ? 

It means that the construction process is made so generic, that multiple products can be produced using the same process. e.g. construction workers. Different type of buildings can be built using the same workers and same common set of process.

Here is a class diagram of the design pattern.

Builder Design Pattern
Builder Design Pattern
There are 4 major components:

  1. Director: It constructs an object using the Builder interface.
  2. Builder : It specifies an abstract interface to build parts of a product.
  3. Concrete Classes : Implements builder interface.
  4. Product : The complex object which is created at the end. 

Director object is created and Builder interface is used. It notifies the Builder to create each part of the product. Upon the request from Director, Builder adds parts to the product. Finally the product is returned by the Builder.

We have to take care of when to use the Builder Design Pattern. Few points come into mind :
  • When the object to be created is complex enough and can have multiple representations.
  • When the construction process can be broken down into multiple steps
  • When the process of creation of an object can be independent of the parts to be used.
  • When different products can have a common abstract class.
Now lets create a builder design pattern using an example.

Builder Design Pattern
Builder Example

In this example we create house as product. Now the house created may be different as per requirement of different people. It can be a lavish house with lots of amenities and expensive stuff. On the other hand, it could be a normal house with normal stuff.

  • The HouseBuilder class is the builder class which provides interface for creating the parts of the house.
  • The House class is the final product that we want to build
  • LavishHouse and NormalHouse are the concrete classes which implement the HouseBuilder interface.
  • Contractor is the director which constructs the house using the HouseBuilder interface.


Builder Design Pattern Implementation(C++)

 #include <iostream>

using namespace std;

/* Interface that will be returned as the product from builder */
class HousePlan{
public:
 virtual void setWindow(string window)=0;
 virtual void setDoor(string door)=0;
 virtual void setBathroom(string bathroom)=0;
 virtual void setKitchen(string kitchen)=0;
 virtual void setFloor(string floor)=0;
};

/* Concrete class for the HousePlan interface */
class House:public HousePlan{
private :
 string window, door, kitchen, bathroom, floor;

public:
 void setWindow(string window)
 {
  this->window = window;
 }

 void setDoor(string door)
 {
  this->door = door;
 }

 void setBathroom(string bathroom)
 {
  this->bathroom = bathroom;
 }

 void setKitchen(string kitchen)
 {
  this->kitchen = kitchen;
 }

 void setFloor(string floor)
 {
  this->floor = floor;
 }
};

/* Builder Class */
class HouseBuilder
{
public:
 /* Abstract functions to build parts */
 virtual void buildWindow()=0;
 virtual void buildDoor()=0;
 virtual void buildKitchen()=0;
 virtual void buildBathroom()=0;
 virtual void buildFloor()=0;
 /* The product is returned by this function */
 virtual House* getHouse()=0;
};

/* Concrete class for the builder interface */
class LavishHouse:public HouseBuilder{
private:
 House *house;
public:
 LavishHouse()
 {
  house = new House();
 }

 void buildWindow()
 {
  house->setWindow("French Window");
 }

 void buildDoor()
 {
  house->setDoor("Wooden Door");
 }

 void buildBathroom()
 {
  house->setBathroom("Modern Bathroom");
 }

 void buildKitchen()
 {
  house->setKitchen("Modular Kitchen");
 }

 void buildFloor()
 {
  house->setFloor("Wooden Floor");
 }

 House* getHouse()
 {
  return this->house;
 }
};

/* Another Concrete class for the builder interface */
class NormalHouse:public HouseBuilder{
private:
 House *house;
public:
 NormalHouse()
 {
  house = new House();
 }

 void buildWindow()
 {
  house->setWindow("Normal Window");
 }

 void buildDoor()
 {
  house->setDoor("Metal Door");
 }

 void buildBathroom()
 {
  house->setBathroom("Regular Bathroom");
 }

 void buildKitchen()
 {
  house->setKitchen("Regular Kitchen");
 }

 void buildFloor()
 {
  house->setFloor("Mosaic Floor");
 }

 House* getHouse()
 {
  return this->house;
 }
};

/* The Director. Constructs the house */
class Contractor
{
private:
 HouseBuilder *houseBuilder;

public:
 Contractor(HouseBuilder *houseBuilder)
 {
  this->houseBuilder = houseBuilder;
 }

 House *getHouse()
 {
  return houseBuilder->getHouse();
 }

 void buildHouse()
 {
  houseBuilder->buildWindow();
  houseBuilder->buildDoor();
  houseBuilder->buildBathroom();
  houseBuilder->buildKitchen();
  houseBuilder->buildFloor();
 }
};

/* Example on how to use the Builder design pattern */
int main()
{
 HouseBuilder *lavishHouseBldr = new LavishHouse();
 HouseBuilder *normalHouseBldr = new NormalHouse();

 Contractor *ctr1 = new Contractor(lavishHouseBldr);
 Contractor *ctr2 = new Contractor(normalHouseBldr);

 ctr1->buildHouse();
 House *house1 = ctr1->getHouse();
 cout<<"Constructed: "<<house1;

 ctr2->buildHouse();
 House *house2 = ctr2->getHouse();
 cout<<"Constructed: "<<house2;
}