This is my interface, all of my transport concrete classes will be implementing this interface.
interface ITransport
{
void Travel()
}
These are my existing implementation class:
class Horse : ITransport
{
public Horse()
{
}
public void Travel()
{
Console.Writeline("I am travelling on a horse");
}
}
class Camel : ITransport
{
public Camel()
{
}
public void Travel()
{
Console.Writeline("I am travelling on a Camel");
}
}
class Ship : ITransport
{
public Ship()
{
}
public void Travel()
{
Console.Writeline("I am travelling on a Ship");
}
}
This is my Factory class I create instance of my transport classes from this factory class.
class TransportFactory
{
public TransportFactory()
{
}
ITransport ProvideTransport(string transportType)
{
switch(transportType)
{
case "Camel": return Camel; break;
case "Horse": return Horse; break;
case "Ship": return Ship; break;
}
}
}
This is my creational class meaning I configure my client classes or consumer classes through this class:
class ConfigurationBuilder
{
ITransport camel;
ITransport ship;
ITransport horse;
public ConfigurationBuilder()
{
TransportFactory tFactory = new TransportFactory();
horse = tFactory.ProvideTransport("horse");
camel = tFactory.ProvideTransport("camel");
ship = tFactory.ProvideTransport("ship");
}
Human ConfigureHuman()
{
return new Human(camel, ship, horse);
}
}
This is my client code the actual caller of these transport class:
class Human
{
ITransport camel;
ITransport ship;
ITransport horse;
public Human(ITransport camel, ITransport ship, ITransport horse)
{
this.camel = camel;
this.ship = ship;
this.horse = horse;
}
void Travel()
{
//TransportFactory tFactory = new TransportFactory();
if(ground =="plain")
{
horse.Travel();
}
if(ground =="desert")
{
camel.Travel();
}
if(ground =="sea")
{
ship.Travel();
}
}
}
Now my question is What will happen when I have a new means of traveling: such as Plane for Air and then Rocket for Space etc.
My Constructor will change and will keep on changing as more and more means of traveling keep on adding throughout application life time. Is this the correct design or is there a better way.
As for the question is considered I couldn't come up with intuitive words to explain my problem :)
Update: Commented TransportFactory out of Human class
Update2:
I guess I now understood how it will be done. I will be needing two factories now.TransportFactory which is already implemented above, the second one will be HumanFactory which will create a human but also has additional responsibility of calling travel method of appropriate ITransport.
public class HumanFactory
{
ITransport camel;
ITransport ship;
ITransport horse;
Human _human;
Dictionary<string, ITransport> _availableTransports;
event Action<Human, string> transportRequested;
public HumanFactory(TransportFactory tFactory)
{
horse = tFactory.ProvideTransport(TransportTypes.Horse);
camel = tFactory.ProvideTransport(TransportTypes.Camel);
ship = tFactory.ProvideTransport(TransportTypes.Ship);
}
public Human ConfigureHuman()
{
if (_availableTransports == null)
{
_availableTransports = new Dictionary<string, ITransport>();
_availableTransports.Add(GroundTypes.Desert.ToString(), camel);
_availableTransports.Add(GroundTypes.Sea.ToString(), ship);
_availableTransports.Add(GroundTypes.Plains.ToString(), horse);
}
transportRequested += new Action<Human, string>(_human_transportRequested);
_human = new Human(transportRequested);
return _human;
}
void _human_transportRequested(Human human, string groundType)
{
if (_availableTransports.ContainsKey(groundType))
{
ITransport suitableTransport = _availableTransports[groundType];
suitableTransport.Travel();
}
else
{
//code for handling below conditions goes here
//I don't know what to do for this type of plain?
}
}
}
Here is the Human class now:
public class Human
{
Action<Human, string> _transportRequested;
public Human(Action<Human, string> transportRequested)
{
_transportRequested = transportRequested;
}
public void Travel()
{
if (_transportRequested != null)
{
var ev = _transportRequested;
ev.Invoke(this, GroundTypes.Plains.ToString());
}
}
}
We will call the Human class now as:
TransportFactory tFactory=new TransportFactory();
HumanFactory humanFactory = new HumanFactory(tFactory);
Human human = humanFactory.ConfigureHuman();
human.Travel();
One More thing: I guess I should be having a lock in the HumanFactory class in _human_transportRequested method? In case there is a multithreaded scenario. I guess now my code is following Law of Demeter :)
Special Thanks to Nik( for that marvelous solution) and Gleb( for those wonderful videos)
return Camel
This won't compile, did you meanreturn new Camel()
? \$\endgroup\$ITransportable
, following a bit of a naming convention. \$\endgroup\$ITransport
is a good name here. \$\endgroup\$