Suppose that we have a file containing the following XML:
<document>
<tagA />
<tagB />
<tagC />
<tag1 />
<tag2 />
<tag3 />
<custom1/>
<custom2/>
</document>
and suppose that we have a parser object to scan the file. For each tag found in the file the parser invokes the corresponding method of a handler object:
class Handler{
function tagA(){ ... }
function tabB(){ ... }
function tagC(){ ... }
function tag1(){ ... }
function tag2(){ ... }
function tag3(){ ... }
function custom1(){ ... }
function custom2(){ ... }
}
Now, suppose that we want to build a framework to handle files of the above type. To ensure code reusability we could split the above class into different (more specialized) classes:
class LettersHandler{
function tagA(){ ... }
function tabB(){ ... }
function tagC(){ ... }
}
class NumbersHandler{
function tag1(){ ... }
function tag2(){ ... }
function tag3(){ ... }
}
To code a handler for the above file the programmer may take advantage of the framework and implement only the missing methods (using OOP inheritance):
class Handler extends LettersHandler, NumbersHandler{
function custom1(){ ... }
function custom2(){ ... }
}
According to the content of the file, the programmer might choose to inherit only from one class, from both (like in the example above) or none.
Now, suppose that the framework supports many pre-build handlers:
class LettersHandler{ ... }
class NumbersHandler{ ... }
class SymbolsHandler{ ... }
etc...
If the programming language supports multiple inheritance, the programmer may inherit from one ore more classes provided by the framework to handle a specific file (according to the tags contained in the file).
Now, my question is:
What is the best way to implement the above situation if the programming language doesn't support multiple inheritance but only supports single inheritance?
Is there an easy way of doing it as using multiple inheritance?
I have read that multiple inheritance is often considered a bad practice, but I really can't understand how to implement the above situation without using it.
Create a base class called TagHandler
.
// A C++ incarnation of such a class.
class TagHandler
{
virtual processTag(std::string const& tagName,
..., // Any additional arguments that makes sense
) = 0;
};
Provide a mechanism for clients to register TagHandler
s based on a tag name. Make some policy decisions about what to do with multiple clients registering handlers for a given tag name. Do you want to raise an exception? Does the last one in win? Do you allow for multiple TagHandlers?
class TagProcessor
{
public:
static void registerTagHandler(std::string const& tagName,
TagHandler* tagHandler)
{
// Do the needful to register the TagHandler based on policy.
}
};
Provide a function that processes tags in a black box manner, in the above class.
class TagProcessor
{
public:
static void processTag(std::string const& tagName,
..., // Any additional arguments that makes sense
)
{
// Look for the TagHandler(s) given the tag name.
// If found, call the processTag() function.
// Deal with non-existing TagHandler.
}
};
Create sub-types of TagHandler
for processing various tags.
class TagAHandler : public TagHandler
{
public:
virtual processTag(std::string const& tagName,
...)
{
// Do the needful to process the tag
}
};
Register the TagHandler
for dealing with "tagA"
TagProcessor::register("tagA", new TagHandler());
Call TagProcessor::processTag
in the parser code.