Re: inheritance headache....
b...@blah.com wrote:
Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;
// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
you not need "else" after "return"
{
return new concreteTarget2();
}
else
{
return 0;
}
}
Not sure about "actually EVERYWHERE", but the job is well-known design
pattern called as Abstract Factory.
The Factory returns concrete set of objects and knowledge about
correct type of returned objects is responsibility of the Factory,
encapsulated by the Factory, why "actually EVERYWHERE"?
Abstract Factory often used as link-time compatible part of program,
so implementation of the Factory is often runtime template (looks like
trivial case of well-known design pattern called as Template Method) -
removing implementation of interface of abstract base class into
derived classes.
Abstract Factory declare interface of creators:
class Abstract_Factory
{
public:
virtual
abstractTarget*
Abstract_Factory::createTarget
(abstractDescription* desc)
=0;
};
Concrete Factory, derived from Abstract Factory, encapsulates concrete
set of returned objects:
namespace N1feb2008{
class Concrete_Factory: public Abstract_Factory
{
public:
abstractTarget*
concrete_Factory::createTarget
(abstractDescription* desc)
{
if ( desc is concreteDesc1)
return new concreteTarget1;
if (desc is concreteDesc2)
return new concreteTarget2;
return 0;
}
};}
namespace N2feb2008{
template
<
class Told_Factory=N1feb2008::Concrete_Factory
>
class Concrete_Factory: public Abstract_Factory
{
Told_Factory old;
public:
abstractTarget*
concrete_Factory::createTarget
(abstractDescription* desc)
{
if ( desc is concreteDesc3)
return new concreteTarget3;
return old.createTarget(desc);
}
};}
Now I CANT add methods to abstractDescription,
if I could I would have a method;
class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}
and each ConcreteDescription subclass would override
as needed the create the right concreteTarget.
BUT I cant do that as the AbstractDesciption family
of objects cannot be modified in any way.
Not sure what does it mean "cannot be modified in any way". There is
well-known design pattern Adapter, that can adapt in fact everything
to everywhere.
In the case, Adapter will add to abstractDescription new method for
new "create" message of new requested interface (class
Adapted_Description).
//compile time template
namespace Nctt
{
//types
//they encapsulate links
//between Target and Description
template<class Tadapted>
struct Tlink;
//
template<>struct
Tlink<concreteDescription1>
{ typedef concreteTarget1 Target; };
//
template<>struct
Tlink<concreteDescription2>
{ typedef concreteTarget2 Target; };
//
template<>struct
Tlink<concreteDescription3>
{ typedef concreteTarget3 Target; };
//end of types
//adapter
template<class Tadapted, class Towner=Tadapted>
class Adapted_Description: public abstractDescription
{
public:
typedef
typename Tlink<Tadapted>::Target
Target;
protected:
Towner adapted;
//new interface
public:
Target* create()
{ return new Target; }
Adapted_Description();
Adapted_Description(const Towner& ad):
adapted(ad);
//old interface
public:
for each
abstractDescription::method
{ adapted.abstractDescription::method; }
};
//namespace Nctt
}
//run time template
namespace Nrtt
{
class Adapted_Description: public abstractDescription
{
//new interface
public:
virtual
AbstractTarget*
create()
=0;
};
template<class Tadapted, class Towner=Tadapted>
class concrete_Description: public Adapted_Description
{
public:
typedef
typename Nctt::Adapted_Description
<Tadapted, Towner>
Nctt_Adapted_Description;
typedef
typename
Nctt_Adapted_Description::Target
Target;
protected:
Nctt_Adapted_Description
adapted;
//Ncct::Adapted_Description interface
for each
Nctt_Adapted_Description ctor
{ concrete_Description():adapted(); }
/*
concrete_Description()
adapted();
concrete_Description(const Towner& ad):
adapted(ad);
*/
/*
//new interface (part of Adapted_Description interface)
public:
Target*
create()
{ return adapted.create(); }
*/
//old interface
public:
for each
Adapted_Description::method
{ adapted.Ncct_Adapted_Description::method; }
};
//namespace Nrtt
}
This can be compiled
void foo()
{
Nctt::Adapted_Description
<concreteDescription1>
tmp;
Nrtt::concrete_Description
<concreteDescription1>
tmp2;
tmp.create();
tmp2.create();
}
declare and define all
class abstractDescription{};
class AbstractTarget{};
class concreteDescription1:
public abstractDescription {};
class concreteDescription2:
public abstractDescription {};
class concreteDescription3:
public abstractDescription {};
class concreteTarget1:
public AbstractTarget {};
class concreteTarget2:
public AbstractTarget {};
class concreteTarget3:
public AbstractTarget {};
and comment "for each" sections and not-defined ctors
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new