If you must do what you suggest, keeping the Feed etc. methods part of the owner not the pet, then you could utilize dynamic binding to call the correct owner method:
using System;
class Pet { }
class Dog : Pet { }
class Cat : Pet { }
class Owner
{
public void HandlePet(Pet pet)
{
HandlePet((dynamic)pet);
}
private void HandlePet(Cat pet)
{
Console.WriteLine("Stroke the cat softly whispering Please don't scratch me.");
}
private void HandlePet(Dog pet)
{
Console.WriteLine("Stroke the dog firmly saying Who's a good boy?");
}
}
class Program
{
static void Main(string[] args)
{
var owner = new Owner();
Console.WriteLine("Handle dog first");
owner.HandlePet(new Dog());
Console.WriteLine("Handle cat second");
owner.HandlePet(new Cat());
Console.ReadKey();
}
}
Output:
Handle dog first
Stroke the dog firmly saying Who's a good boy?
Handle cat second
Stroke the cat softly whispering Please don't scratch me.
If you can avoid it, then I would put the methods on the Pet classes, as below:
One way would be to make Pet an abstract class, which has EatFood
and Play
abstract methods. The Dog
and Cat
classes would implement these methods:
using System;
abstract class Pet
{
public abstract void EatFood();
public abstract void Play();
public void BrushHair()
{
Console.WriteLine("Hair brushed!");
}
}
class Dog : Pet
{
public override void EatFood()
{
Console.WriteLine("Eating dog food...");
}
public override void Play()
{
Console.WriteLine("Run around manically barking at everything.");
}
}
class Cat : Pet
{
public override void EatFood()
{
Console.WriteLine("Eating cat food...");
}
public override void Play()
{
Console.WriteLine("Randomly choose something breakable to knock over.");
}
}
class Owner
{
public void HandlePet(Pet pet)
{
pet.EatFood();
pet.Play();
pet.BrushHair();
}
}
class Program
{
static void Main(string[] args)
{
var owner = new Owner();
Console.WriteLine("Handle dog first");
owner.HandlePet(new Dog());
Console.WriteLine("Handle cat second");
owner.HandlePet(new Cat());
Console.ReadKey();
}
}
Output:
Handle dog first
Eating dog food...
Run around manically barking at everything.
Hair Brushed!
Handle cat second
Eating cat food...
Randomly choose something breakable to knock over.
Hair Brushed!
If you want to use the visitor pattern, try the code below:
using System;
public interface IPetVisitor
{
void Visit(Dog dog);
void Visit(Cat cat);
}
public interface IPetAcceptor<T>
{
void Accept(T visitor);
}
public abstract class Pet : IPetAcceptor<IPetVisitor>
{
public abstract void Accept(IPetVisitor visitor);
}
public class Dog : Pet
{
public override void Accept(IPetVisitor visitor)
{
visitor.Visit(this);
}
}
public class Cat : Pet
{
public override void Accept(IPetVisitor visitor)
{
visitor.Visit(this);
}
}
class Owner
{
// Private variable on owner class
private int HandCount = 2;
// Pet handler is an inner class so we can access the enclosing class' private member.
public class PetHandler : IPetVisitor
{
private Owner Owner;
public PetHandler(Owner owner)
{ Owner = owner; }
public void Visit(Dog dog)
{
Console.WriteLine("Pet the dog with {0} hands", Owner.HandCount);
}
public void Visit(Cat cat)
{
Console.WriteLine("Pet the cat with {0} hands", Owner.HandCount);
}
}
private PetHandler PetHandlerInstance;
public Owner()
{
PetHandlerInstance = new PetHandler(this);
}
public void HandlePet(IPetAcceptor<IPetVisitor> pet)
{
pet.Accept(PetHandlerInstance);
}
}
class Program
{
static void Main(string[] args)
{
var owner = new Owner();
Console.WriteLine("Handle dog first");
owner.HandlePet(new Dog());
Console.WriteLine("Handle cat second");
owner.HandlePet(new Cat());
Console.ReadKey();
}
}