'How should 2 similar static factory classes be related?

Say I have a class for Person which I want to implement as a static factory:

public class Person {
    private String name;
    private Double heightInMeters;
    
    private Person(String name, Double meters) {
      this.name = name;
      this.heightInMeters = meters;
    }
  
    public static Person fromNameAndCentimeters(String name, Double centimeters) {
      return new Person(name, centimeters/100.0);
    }
  
    public static Person fromNameAndInches(String name, Double inches) {
      return new Person(name, inches/3.28);
    }
  
    public string toString() {
      return "My name is " + name + " and my height in meters is " + heightInMeters;
    }
}

But I also have a nearly identical class Jeff for which I want to have slightly different factory methods:

public class Jeff {
    public static final JEFF_NAME = "Jeff";

    private String name = JEFF_NAME;
    private Double heightInMeters;
    
    private Jeff(String name, Double meters) {
      this.name = name;
      this.heightInMeters = meters;
    }
  
    public static Jeff fromCentimeters(Double centimeters) {
      return new Jeff(name, centimeters/100.0);
    }
  
    public static Jeff fromInches(Double inches) {
      return new Jeff(name, inches/3.28);
    }
  
    public String toString() {
      return "My name is " + name + " and my height in meters is " + heightInMeters;
    }
}

Clearly, Jeff and Person are related, and I want to do something like

public printIntroduction(Object somebody) {
    System.out.println(somebody);
}
printIntroduction(Person.fromNameAndInches("Bob", 65))
printIntroduction(Jeff.fromInches(60))

My first thought was to have Jeff inherit from Person - but child classes inherit static methods, and I don't want Jeff to have fromNameAndInches. What's the best way to go about this?



Solution 1:[1]

I am trying to use inheritance when derived classes should have the same behavior like base class. So the public methods should be the same in base and derived classes. So, abstract class should define behavior, and the derived classes should implement that behavior.

But, there is no the same behavior in your example classes. So we cannot use inheritance here. However, we can improve code by reducing duplication of code of conversion to meters:

public class Conversion
{
    public double FromCentimetersToMeters(double centimeters) 
    {
        return centimeters / 100.0;
    }


    public double FromInchesToMeters(double inches)
    {
        return inches / 3.28;
    }
}

and then Person will be looked like this:

public class Person
{
    public string Name { get; private set; }

    public double Height { get; private set; }


    Conversion conversion = new Conversion();


    public Person(string name, double height)
    {
        Name = name;
        Height = height;
    }


    public Person FromNameAndCentimeters(string name, double centimeters)
    {
        return new Person(name, conversion.FromCentimetersToMeters(centimeters));
    }

    
    public Person FromNameAndInches(string name, double inches)
    {
        return new Person(name, conversion.FromInchesToMeters(inches));
    }
}

and Jeff class:

public class Jeff
{
    public string Name { get; set; } = "Jeff";


    public double Height { get; private set; }


    Conversion conversion = new Conversion();


    public Jeff(double height)
    {
        Height = height;
    }


    public Jeff FromCentimeters(double centimeters)
    {
        return new Jeff(conversion.FromCentimetersToMeters(centimeters));
    }


    public Jeff FromInches(double inches)
    {
        return new Jeff(conversion.FromInchesToMeters(inches));
    }
}

And then you can easily write unit tests for Conversion class to check whether the logic of conversion is correct.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 StepUp