Pregunta

I have 10-15 different types of results to calculate say AResult, BResult etc. All result calculation return single type of value(consider an integer value). To calculate these I needs input parameters which are mostly common but a few needs different ones as follows:

Input parameters example:
    AResult needs  int x, int y, int a[], int b[]
    BResult needs  int x, int y, int a[], boolean c
    CResult needs  int x, int y, int a[], boolean c, boolean d
    DResult needs  int x, int y, int p[], boolean e
    .....

NOTE that in some cases result of one calculation is also used in other result calculations, but that is only in few cases and not all.

The way I am doing it is through Approach1 as follows:

Approach 1:

I am defining an interface which has single method to calculate result taking an InputParameter obj. In the implementation classes I would extract out the values from InputParameter obj whichever are applicable to that particular type of result. Here is the snippet of my sample code:

public interface Result {
    int calculate(InputParameter obj);
}

public class AResult implements Result {
    public int calculate(InputParameter obj){
      // code
     }

}

public class BResult implements Result {
    public int calculate(InputParameter obj)){
      // code
     }


}

public class InputParameter {
    int x;
    int y;
    int z;
    int a[];
    int b[];
    int p[];
    boolean c;
    boolean d;
    boolean e;
    ....
    // Getters and Setters
}

As an example, say I create an InputParameter object and set values of all the fields in there. I pass this object to aResultObject.calculate(InputParameter obj) , dResultObject.calculate(InputParameter obj) and so on.

AResult needs int x, int y, int a[], int b[] which I extract from InputParameter obj do the calulations and return result.

DResult needs int x, int y, int p[], boolean e which I extract from same InputParameter obj to do the calulations and return result.

Note that I might have to do other sets of result calculations, so may create multiple objects of InputParameter, AResult, BResult so on. Just want to convey that InputParameter need not be singleton.


Approach2:

Having calculate() method without any parameter and setting these values in individual Result class constructors.

As @Duncan pointed out one drawback of Approach1 is that, here I might miss setting the required fields in InputParameter object for a given result calculation. And when I actually try to extract out the value from InputParameter object in calculation(InputParameter obj) method, I discover it is not set.

public interface Result {
   int calculate();
}

public class AResult implements Result {
   public AResult(int x, int y, int a[], int b[]) {
      //set input params
   }
   public int calculate() {
      //calculate and return AResult
   }
}

Approach3:

Create Single class (or may be just 2-3 classes) for Result and then just have separate methods to calculate different results.

I am also considering this approach because in some cases result of one calculation is also used in other result calculations (but that is only in few cases and not all).

public class Result {
   // various fields...

   int calculateResultA(){...}
   int calculateResultB(){...}
   int calculateResultC(){...}
}

Is the above mentioned Approach1 good for given situaltion? or the other alternatives are better?

¿Fue útil?

Solución

I suggest approach 2 with a factory. The pattern is (maybe) command.

Factory approach

package blammy.result;

public interface Result
{
    int calculate();
}

package blammy.result.impl;

public class AResult
implements Result;
{
    /*
     * Protected constructor to hinder naughty construction.
    */
    protected AResult(
        int x,
        int y,
        int a[],
        int b[])
    {
        ... blah;
    }

    public int calculate()
    {
        int returnValue;
        returnValue = ... blah.
        return returnValue;
    }
}
public class BResult
implements Result;
{
    /*
     * Protected constructor to hinder naughty construction.
    */
    protected BResult(
        int x,
        int y,
        boolean c)
    {
        ... blah;
    }

    public int calculate()
    {
        int returnValue;
        returnValue = ... blah.
        return returnValue;
    }
}

public static class ResultFactory
{
    public static Result createResult(
        int x,
        int y,
        int a[],
        int b[])
    {
        return new AResult(x, y, a, b);
    }

    public static Result createResult(
        int x,
        int y,
        boolean c)
    {
        return new BResult(x, y, c);
    )
}

Edit 1

If different calculations require the same parameters, then you should use descriptive name in the factory and in the class name. For example:

public static class ResultFactory

    public static Result createBlammy(
        int x,
        int y,
        int a[],
        int b[])
    {
        return new ResultBlammy(x, y, a, b);
    }

    public static Result createHooty(
        int x,
        int y,
        int a[],
        int b[])
    {
        return new ResultHooty(x, y, a, b);
    }

Otros consejos

In my opinion, use constructor and define the interface Result to have a method public int calculate() which take no parameter.

DISCLAIMER from this point on, are personal interpretations of a couple of good principles. Evaluate them, criticize them if you do not agree and do not take them for given facts (the principles are really good, the interpretation in your case may be not that good).

I will try to avoid using objects having low cohesion, where cohesion is defined in the book Growing object oriented software guided by tests as

An element’s cohesion is a measure of whether its responsibilities form a meaningful unit. For example, a class that parses both dates and URLs is not coherent, because they’re unrelated concepts. Think of a machine that washes both clothes and dishes—it’s unlikely to do both well.2 At the other extreme, a class that parses only the punctuation in a URL is unlikely to be coherent, because it doesn’t represent a whole concept. To get anything done, the programmer will have to find other parsers for protocol, host, resource, and so on. Features with “high” coherence are easier to maintain.

In your case, I believe InputParameter has the responsibility to hold parameter for different classes, so in my opinion its responsibility is not a meaningful unit (and even if it is basically a value object, by some extension it violates the Single Responsibility Principle)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top