DEV Community

Discussion on: Casting stinks. Generic classes are worse.

Collapse
sam_ferree profile image
Sam Ferree • Edited on

***Sorry for clicking "Edit Post" like 20 times, but I kept thinking of more ways interfaces really help here.

Code to interfaces, not concrete implementations?

public interface IEngineer
{
  //Engineer Properties
}

public class LeadEngineer : IEngineer
{
  //Lead Implementation
}

public interface IAssemblyLineInstructions { }
public class SedanAssemblyLineInstructions : IAssemblyLineInstructions {}
public interface IVehicle {}
public interface IAssemblyLine {}

public class AssemblyLine
{
  private IVehicle _vehicle;
  private IEngineer _enginee;
  private IAssembyLineInstructions _instructions
}

public interface IFactory 
{
  public IAssemblyLine { get; }
}

public interface INamedFactory : IFactory
{
  string FactoryName { get; }
}

public abstract class VehicleFactory : INamedFactory
{
  public string FactoryName { get; set; }
  public IAssemblyLine AssemblyLine { get; set; }
}

public void Print(INamedFactory factory)
{
  Console.WriteLine($"Welcome to {factory.FactoryName}");
  Console.WriteLine($"The Engineer on duy is {factory.AssemblyLine.Engineer.Name}");
}

public class SedanAssemblyLine : IAssemblyLine
{
  //Assembly lines have engineers
  public IEngineer Engineer { get; set; }
  public SedanAssemblyLine()
  {
    // Set defaults in the constructor, not using generics.
    // This assembly lines engineer is a SedanEngineer
    Engineer = new SedanEngineer();
  }
}

if you have functionality that you're wrapping, that's fine too.
define an abstract class that contains common functionality, and make sure it implements the interface, then just subclass it and set your custom implementations in the constructors of base classes

public interface IFactory
{
  public IAssemblyLine AssemblyLine { get; }
  public void PrintEngineer();
}

public abstract class Factory : IFactory
{
  public IAssemblyLine AssemblyLine { get; set; }
  //All factories will do this, in the same way, so Don't Repeat Yourself
  public void PrintEngineer()
  {
    Console.WriteLine("The engineer is ${AssemblyLine.Engineer.Name}");
  }
}

public class SedanFactory : Factory
{
  public SedanFactory()
  {
    //Sedan Factories have Sedan Assembly Lines... Obviously....
    AssemblyLine = new SedanAssemblyLine();
  }
}
Collapse
rrconstantin profile image
rrconstantin

That is exactly how I would approach the problem. This approach is a combination of SOLID principles (interface segregation and dependency inversion mostly) and Bridge pattern (decouple an abstraction from its implementation so that the two can vary independently). Also,

"if you have functionality that you're wrapping, that's fine too.",

we can use Template pattern here.