Andreas Huber said:
cody wrote: [snip]
Iam not sure yet was the "indirect visitor" pattern is but iam sure
it can be better
solved using composition or interfaces.
It would be great if you could explain me a little about "indirect
visitor".
Sorry, I meant "acyclic visitor". Here's a good article:
http://www.objectmentor.com/resources/articles/acv.pdf
The base classes in acyclic visitor are abstract (no implementation), and
therefore, they can be expressed as interfaces. While C# does not support
multiple inheritance of classes, it does support multiple inheritance of
interfaces which makes implementing acyclic visitor in C# trivial (see
below).
That said, there are probably legitimate uses of MI where base classes have
implementation, too. In this case you could use composition or delegates to
get similar functionality.
using System;
namespace AcyclicModemVisitor
{
// IVisitor is a degenerate base interface for all visitors.
public interface IVisitor
{
}
// We could make this into an interface, too.
public abstract class Modem
{
public abstract void Accept(IVisitor visitor);
}
public interface IHayesModemVisitor
{
void Visit(HayesModem hm);
}
public class HayesModem : Modem
{
public override void Accept(IVisitor visitor)
{
IHayesModemVisitor hv = visitor as IHayesModemVisitor;
if (hv != null)
{
hv.Visit(this);
}
else
{
Console.WriteLine("*** ERROR: {0} cannot visit HayesModem",
visitor.ToString());
}
}
}
public interface IZoomModemVisitor
{
void Visit(ZoomModem zm);
}
public class ZoomModem : Modem
{
public override void Accept(IVisitor visitor)
{
IZoomModemVisitor zv = visitor as IZoomModemVisitor;
if (zv != null)
{
zv.Visit(this);
}
else
{
Console.WriteLine("*** ERROR: {0} cannot visit ZoomModem",
visitor.ToString());
}
}
}
//-------------------------
// ConfigureForDOSVisitor
//
// This visitor configures both Hayes and Zoom modems
// for DOS.
//
public class ConfigureForDOSVisitor : IVisitor, IHayesModemVisitor,
IZoomModemVisitor
{
public void Visit(HayesModem hm)
{
Console.WriteLine("ConfigureForDOSVisitor visiting {0}", hm);
}
public void Visit(ZoomModem zm)
{
Console.WriteLine("ConfigureForDOSVisitor visiting {0}", zm);
}
}
//--------------------------
// ConfigureForUnixVisitor
//
// This visitor configures only Zoom modems for Unix
//
public class ConfigureForUnixVisitor : IVisitor, IZoomModemVisitor
{
public void Visit(ZoomModem zm)
{
Console.WriteLine("ConfigureForUnixVisitor visiting {0}", zm);
}
}
class MainClass
{
[STAThread]
static void Main(string[] args)
{
// Create a bunch of modems to visit -
// in DOS, we have both Zoom and Hays modems
Modem[] dosModems = new Modem[] {
new ZoomModem(),
new HayesModem(),
new ZoomModem(),
new HayesModem()
};
// In Unix, we have only Zoom modems
Modem[] unixModems = new Modem[] {
new ZoomModem(),
new ZoomModem()
};
Console.WriteLine("Visiting DOS modems...");
ConfigureForDOSVisitor dosVisitor = new
ConfigureForDOSVisitor();
foreach (Modem modem in dosModems)
{
modem.Accept(dosVisitor);
}
Console.WriteLine("\nVisiting Unix modems...");
ConfigureForUnixVisitor unixVisitor = new
ConfigureForUnixVisitor();
foreach (Modem modem in unixModems)
{
modem.Accept(unixVisitor);
}
Console.WriteLine("\nTrying to visit DOS modems with Unix
visitor...");
foreach (Modem modem in dosModems)
{
modem.Accept(unixVisitor);
}
}
}
}