简体   繁体   中英

Java- Should I extend my class or add it into my base class?

I am creating java project which takes in two arrays and calculates a linear regression.

I have 4 classes, one that is a constructor (RegressionModel), one that does the math equations (Math1) and contains all the formulas, a computational class (FinalLinearRegressionModel) which extends the constructor class which I initialize a super constructor and use the values to make methods which call my Math class. Finally I have my tester class which calls the FinalLinearRegressionModel and does the computations from there.

Is this the right way to go about this or should I just put the methods I have inside the FinalLinearRegressionModel into my RegressionModel, and I would therefore have no need to extend my constructor because I am not adding any instance variables into my constructor? Here are my classes:

public class RegressionModel {

    public static final double[] DEFAULT_X = new double[0];
    public static final double[] DEFAULT_Y = new double[0];
    public static final boolean DEFAULT_ISCALCULATED = false;

   public double [] xValues;
   public double [] yValues;
   public boolean isCalculated;

   public RegressionModel()
   {
       xValues = DEFAULT_X;
       yValues = DEFAULT_Y;
       isCalculated = DEFAULT_ISCALCULATED;
   }

   public RegressionModel(double[] x, double[] y)
   {
       if(x == null || y == null)
       {
           System.out.println("Fatal Error creating regression model.");
           System.exit(0);
       }
       else if(x.length == 0 || y.length == 0)
       {
           System.out.println("Fatal Error one or more zero lengths.");
           System.exit(0);
       }
       else if(x.length != y.length)
       {
           System.out.println("Fatal Error array lengths are not equal.");
       }

       else
       {
           xValues = x;
           yValues = y;
           isCalculated = false;
       }
   }

   public double[] getXValues()
   {
       return this.xValues;
   }

   public double[] getYValues()
   {
       return this.yValues;
   }
}



   public class Math1 extends RegressionModel {

    public static double covariance(double[] x, double[] y)
    {
        double meanX;
        double meanY;
        double covariance;
        meanX = mean(x);
        meanY = mean(y);
        covariance = 0;

        for(int index = 0; index < x.length; index++)
        {
            covariance += (x[index] - meanX) * (y[index] - meanY);
        }
        covariance /= (x.length -1);

        return covariance;
    }

    public static double mean(double[] values)
    {
        double sum;
        sum = 0.0;

        for(int index = 0; index < values.length; index++)
        {
            sum += values[index];
        }

        return sum / values.length;
    }

    public static double xxBar(double[] x)
    {

        double xxbar;
        xxbar = 0.0;

        for(int index = 0; index < x.length; index++)
        {
            xxbar += (x[index] - mean(x)) * (x[index] - mean(x));
        }
        return xxbar;
    }

    public static double yyBar(double[] y)
    {
        double yybar;
        yybar = 0.0;

        for(int index = 0; index < y.length; index++)
        {
            yybar += ((y[index] - mean(y)) * (y[index] = mean(y)));
        }
        return yybar;
    }

    public static double xyBar(double[] x, double[] y)
    {
        double xybar;
        xybar = 0.0;

        for(int index = 0; index < x.length; index++)
        {
            xybar += ((x[index] - mean(x)) * (y[index] - mean(y)));
        }
        return xybar;
    }

    public static double beta1(double[] x, double[] y)
    { 
        return xyBar(x,y)/xxBar(x);
    }

    public static double beta0(double[] x, double[] y)
    {
        return mean(y) - beta1(x,y) * mean(x);
    }


   public static double sumOfSquaresDueToRegression(double[] y)
   {
       double meanY;
       meanY = mean(y);

       double sumOfSquaredDeviations = 0.0;
       for(int index = 0; index < y.length; index++)
       {
           sumOfSquaredDeviations += (Math.pow(y[index] - meanY, 2));
       }

       return sumOfSquaredDeviations;

   }

   public static double sumOfSquaresTotal(double[] y)
   {
       double sumOfSquaresTotal;
       sumOfSquaresTotal = 0.0;
       for(int index = 0; index < y.length; index++)
       {
           sumOfSquaresTotal += (Math.pow(y[index] - mean(y), 2));
       }
       return sumOfSquaresTotal;
   }

   public static double degreesOfFreedom(double[] x)
   {
       return x.length - 2;
   }



    public static double fit(double[] x, double[] y)
       {
           double fit;
           fit = 0.0;
           for(int index = 0; index < x.length; index++)
           {
               fit =  beta1(x,y) * x[index] + beta0(x,y);
           }
           return fit;
       }

       public static double r2(double[] y)
       {
          return sumOfSquaresDueToRegression(y) / yyBar(y);
       }


       public static double sumOfSquaresDueToError(double[] x, double[] y)
       {
           double sumOfSquaresError;
           sumOfSquaresError = 0.0;
           for(int index = 0; index < y.length; index++)
           {
               sumOfSquaresError += (Math.pow(y[index] - beta1(x,y), 2));
           }
           return sumOfSquaresError;
       } 
    }
public class FinalLinearRegressionModel extends RegressionModel{

   public double b0;


    public FinalLinearRegressionModel(double[] x, double[] y)
    {
        super(x,y);
    }

    public double computeb0()
    {
       return b0 =  Math1.beta0(xValues,yValues);
    }

}

    public class Test {
    public static void main(String args[])
    {
        double[] x = {2, 3, 4, 5, 6, 8, 10, 11};
        double[] y = {21.05, 23.51, 24.23, 27.71, 30.86, 45.85, 52.12, 55.98};

        FinalLinearRegressionModel regression1;

        regression1 = new FinalLinearRegressionModel(x,y);

        System.out.println(regression1.computeb0());

    }       
}

Move your computeb0() method up into RegressionModel and get rid of FinalLinearRegressionModel .

Also why does Math1 extend RegressionModel ? All the methods are static so it doesn't use any of the instance fields of RegressionModel.

Next, computeb0 method's return looks weird:

 return b0 =  Math1.beta0(xValues,yValues);

is returning the result of the assignment which I think happens to be the correct answer but that is not a common idiom in java programming and will confuse others who read your code.

b0 =  Math1.beta0(xValues,yValues);
return b0;

would what you want

Even better would be not to save b0 to an instance value at all. There's no need

return Math1.beta0(xValues,yValues);

Finally, as mentioned by Commenter Chief Two Pencils, calling System.exit() in a constructor is bad form. You should throw an exception instead:

   //don't need else keyword in this case
   if(x == null || y == null)
   {
       throw new NullPointerException("x and y can not be null");
   }

   if(x.length == 0 || y.length == 0)
   {
       throw new IllegalArgumentException("one or more zero lengths.");
   }
   if(x.length != y.length)
   {
      throw new IllegalArgumentException("array lengths are not equal.");
   }

RegressionModel represent your vertices. They could have been stored as an array of Vertice , but you choose a separate double [] for x and y which is also fine.

However my advice is because your model is quite simple, not to introduce any new 'Uber' model for your array or list. Just let it be what it is. Either a List or an array. Maybe even better: do implement your Vertice as an actual Vertice class, so you can represent your model as either List<Vertice> or Vertice [] . You can add static helper methods in Vertice to create your List or array out of your double [] arrays.

import java.util.Arrays;
import java.util.List;

public class Vertice {
  final public double x;
  final public double y;
  public Vertice(double x,double y) {
    this.x = x;
    this.y = y;
  }

  static public Vertice [] arrayFrom(double [] xs,double [] ys) {
    // Allow to below automatically throw a NullPointerException without explicitly checking
    if (xs.length != ys.length) throw new IllegalArgumentException("Arrays of diferent size: "+xs.length+" != "+ys.length);
    Vertice [] vs = new Vertice[xs.length];
    for (int i=0;i<xs.length;i++) vs[i] = new Vertice(xs[i],ys[i]);
    return vs;
  }

  static public List listFrom(double [] xs,double [] ys) {
    return Arrays.asList(arrayFrom(xs,ys));
  }
}

So gone is RegressionModel . As explained by @dkatzel, there is also no need to extend the model into Math1 , as it contains only calculations. And actual maybe 'model' here could mean your mathematical model, so as your RegressionModel is not used anymore to represent your vertices, you can now directly rename Math into RegressionModel .

At first glance - with earlier suggestions - it looks nice and clean, but likely you will run into issues that will require a less elegant solution. Example an avg(double[]) now needs to be separately an avgX(List<Vertice>) and avgY(List<Vertice>) .

But hey, now enter the world of Stream and parallel processing. Maybe you can refactor everything to take advantage of Java 8:

import java.util.List;

public class RegressionApp {
    public static void main(String args[])
    {
        double[] x = {2, 3, 4, 5, 6, 8, 10, 11};
        double[] y = {21.05, 23.51, 24.23, 27.71, 30.86, 45.85, 52.12, 55.98};

        List<Vertice> v = Vertice.listFrom(x, y);
        RegressionModel regression1 = v.stream().parallel()
            .collect(RegressionModel.summarize());;

        System.out.println(regression1.b0);

    }   
}

Would that not be something?

That would be probably a lot of work implementing - but I just couldn't let it go without mention.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM