//
Purpose.  Extension Object design
pattern.
// 
// Summary. 
Discusses how to use aggregation (instead of mixin multiple
//
inheritance) to add "interfaces" (or methods) to a class at
run-time.
// This approach overcomes some limitations in the Visitor and
Decorator
// patterns - but - it requires the use of RTTI, and, it makes
client code
// more complex.
// 
// Whereas Decorator requires
that the core class's interface remain fixed
// as successive
"wrappers" are applied, Extension Object allows the class's
//
interface to grow incrementally and dynamically.
// 
// The focus of
the Extension Object pattern is to engineer a class to
// support
additional methods, or services. 
Clients that want to leverage
// an interface extension, query the
object first to see if it supports
// the extension before attempting to
use it.
// 
// The pattern can tempt the designer to rely on this
technique to
// rationalize reactive coding rather than commit oneself to
proactive
// design.  The paper
offered no discussion of access to private and
// protected members of
Image by Extension objects.
#include <iostream>
#include
<string>
using std::cout;
using std::string;
class
Extension {
public:
   virtual
~Extension() { }
   void
registerOwner( class Image* o ) { owner = o; }
protected:
   Image* owner;
};
class
MosaicExtension : public Extension { public:
   void doMosaic();
};
class HeatExtension : public
Extension { public:
   void
doThermalSpectrum();
};
class Image {
   string name;
public:
   Image( string n ) : name(n) { }
   string getName()  { return name; }
  
void display()    { cout <<
"display: " << name << '\n'; }
   virtual Extension* getExtension( const
type_info& ) { return 0; }
};
void
MosaicExtension::doMosaic() {
  
cout << "  doMosaic:
" << owner->getName() << '\n'; }
void
HeatExtension::doThermalSpectrum() {
  
cout << " 
doThermalSpectrum: " << owner->getName() << '\n';
}
class Lsat : public Image {
   Extension*  exten;
public:
   Lsat( string n, Extension* ex ) : Image( n
) {
      exten = ex;
      exten->registerOwner( this );
   }
  
~Lsat() { delete exten; }
  
/*virtual*/ Extension* getExtension( const type_info& ti ) {
      if (typeid(MosaicExtension) == ti)
return exten;
      return
Image::getExtension( ti );
  
}
};
class IR : public Image {
   Extension* 
exten;
public:
   IR(
string n, Extension* ex ) : Image( n ) {
      exten = ex;
     
exten->registerOwner( this );
  
}
   ~IR() { delete exten;
}
   /*virtual*/ Extension*
getExtension( const type_info& ti ) {
      if (typeid(HeatExtension) == ti) return exten;
      return Image::getExtension( ti );
   }
};
void main( void
) {
   Image* images[4] = {
      new Lsat( "Western
hemisphere", new MosaicExtension() ),
      new IR( "Desert Storm",         new MosaicExtension()  
),
      new Lsat(
"Amazon rain forest", new HeatExtension() ),
      new IR( "Gulf of Oman",         new HeatExtension()   ) };
   Extension*       
ext;
  
MosaicExtension* 
mosaicExt;
  
HeatExtension*    heatExt;
   for (int i=0; i < 4; i++) {
      images[i]->display();
      if (ext = images[i]->getExtension(
typeid(MosaicExtension) )) {
        
if (mosaicExt = dynamic_cast<MosaicExtension*>( ext ))
            mosaicExt->doMosaic();
      } else if (ext =
images[i]->getExtension( typeid(HeatExtension) )) {
         if (heatExt =
dynamic_cast<HeatExtension*>( ext ))
            heatExt->doThermalSpectrum();
   } 
}
   for (i=0; i < 4;
i++) delete images[i];
}
// display: Western hemisphere
//   doMosaic: Western hemisphere
//
display: Desert Storm
// display: Amazon rain forest
// display: Gulf
of Oman
//   doThermalSpectrum:
Gulf of Oman