Question

My question is, how to redesign abstract factory.

For example, I get next abstraction of vehicles:

interface IEngine { int Power(); }
class Gasoline : IEngine { public int Power() {return 150; }}
class Diesel : IEngine { public int Power() { return 50; }}

interface IFrame { string Name(); }
class Boxed : IFrame { public string Name() { return "Boxed frame"; }}
class Hat : IFrame { public string Name() { return "Hat frame"; }}

interface TransportFactory { 
  IEngine CreateEngine(); 
  IFrame CreateChassis(); 
}
class TrailerCar : TransportFactory { 
  public IEngine CreateEngine() { return new Diesel(); }
  public IFrame CreateChassis() { return new Boxed(); }
}
class PrivateCar : TransportFactory {
    public IEngine CreateEngine() { return new Gasoline(); }
    public IFrame CreateChassis() { return new Hat(); }
}

Now, I can instantiate private or trailer car.

Some one suggest me changes: engine for trailers cars can by turbo or hybrid. Only for trailers! For private car diesel and gasoline engines still usual diesel engine. So, if i do changes:

public enum EngineType { Hybrid, Turbo, }

interface TransportFactory
{
    IEngine CreateEngine(EngineType t);
    IFrame CreateChassis();
}

and i can add classes:

class GasolineHybrid : IEngine
{
    public int Power()
    {
        return 70;
    }
}

class GasolineTurbo : IEngine
{
    public int Power()
    {
        return 170;
    }
}

class DieselHybrid : IEngine
{
    public int Power()
    {
        return 60;
    }
}

class DieselTurbo : IEngine
{
    public int Power()
    {
        return 98;
    }
}

it is good, but (!!!) private car nothing to do with it!!! What kind of design can i use? Old abstraction get incorrect?

Thanks a lot!!!

Was it helpful?

Solution

How about:

class GasolineHybridTrailerCar : TransportFactory
{
    public IEngine CreateEngine()
    {
        return new GasolineHybrid();
    }
    ...
}

class GasolineTurboTrailerCar : TransportFactory
{
    public IEngine CreateEngine()
    {
        return new GasolineTurbo();
    }
    ...
}

class DieselHybridTrailerCar : TransportFactory
{
    public IEngine CreateEngine()
    {
        return new DieselHybrid();
    }
    ...
}

class DieselTurboTrailerCar : TransportFactory
{
    public IEngine CreateEngine()
    {
        return new DieselTurbo();
    }
    ...
}

The idea behind spawning numerous classes is to remove client's ability to do wrong choice. Since you said hybrid and turbo engines do not make sense for private cars, then keeping IEngine CreateEngine(EngineType t); will require from private car factory additional efforts to refuse incorrect arguments.

I am not sure did you mean it, but class names suggest that cars are products of factory. In classic relation it will be factory --produce--> product. It is kinky and fun how you put it via generalization, but could be hardly recognizable by others. The beauty of patterns is that once you hear its one word name, then you feel confident about all the internals the implementation could imply.

There is pattern Builder. Would it be more suitable name for your design?

OTHER TIPS

Remember that parameters need not be part of the interface, they can be passed to the constructor of the implementation. So you can still keep your old interface:

interface TransportFactory
{
    IEngine CreateEngine();
    IFrame CreateChassis();
}

but pass the EngineTypeto the TrailerCar constructor:

class TrailerCar : TransportFactory { 
  private readonly EngineType engineType;

  public TrailerCar(EngineType engineType)
  {
    this.engineType = engineType;
  }

  public IEngine CreateEngine()
  {
    if (engineType == EngineType.Hybrid) return new DieselHybrid();
    else return new DieselTurbo();
  }

  public IFrame CreateChassis() { return new Boxed(); }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top