Java:何时使用属性,何时使用方法参数?

时间:2014-03-27 23:06:20

标签: java class oop api-design

我尝试谷歌搜索并搜索这个问题,但不知何故找不到任何相关的问题。我想知道是否有关于何时在类中使用属​​性的bbest-practice指南,何时不使用,而是使用单个方法的参数。

我很清楚很多情况,例如

public class Dog
{
 private name;
 public setName(...) {....}
}

但有时我不清楚使用什么更好。 例如。以下,使用:

public class calculation
  XYZ bla;
  public calculation(XYZ something)
  {
    this.bla = something;
  }
  public void calc1()
  {
    // some calculations with this.bla
  }
  public void calc1()
  {
    // some more calculations with this.bla
  }
  public XYZ getBla()
  {
    return this.bla;
  }
}

或者可能:

public class calculation
  public calculation() {}
  public static XYZ calc1(XYZ bla) // maybe static, if not dependant on other attributes/instance-variables etc
  {
    // some calculations with bla
    return bla;
  }
  public static XYZ calc1() // maybe static, if not dependant on other attributes/instance-variables etc
  {
    // some more calculations with bla
    return bla;
  }
}

我的意思是你可以争辩这两种情况。我看到两种不同风格的优点和缺点,但只要不需要太多参数/参数,我就更喜欢第二种风格。当然,如果我需要更多的属性等,那么第一个属性会更好,更简单等等,因为我不需要将这么多参数传递给方法......

只是个人风格的问题? 或者如何决定一种方法? 感谢


编辑:一个更好的例子:我正在进行大量的图像处理,并且问题是将图像内部存储在对象的状态或不存在。我目前没有这样做,因为我正在使用静态方法,并将图像自身I压缩到每个方法:

public class ImageProcessing
{
    /**
     * 
     */
    public static Mat cannyEdges(Mat I, int low, int high)
    {      
        // ...
        return I;
    }
    public static Mat cannyEdges(Mat I)
    {
        return ImageProcessing.cannyEdges(I, ContourDetection.CANNY_LOWTHRES, ContourDetection.CANNY_HIGHTHRES);
    }

    /**
     * 
     */
    public static Mat getHoughLines(Mat Edges, ...some_conf_vars...)
    {
        // ...
        return I;
    }
}

然后我就这样从外面打电话,例如:

// here: read image to I...
Mat edges = ImageProcessing.cannyEdges(I, 20, 100);
Mat lines = ImageProcessing.getHoughLines(I);

// draw lines...

问题是:I是否属于对象的状态?转换为非静态然后使用例如:

是否有意义
// here: read image to I...
ImageProcessing IP = new ImageProcessing(I);
IP.cannyEdges(20, 100); // CHANGE OF cannyEdges: Also save `edges` internally as property!?
IP.calcHoughLines(); // also save the lines internally maybe?
Mat lines = IP.getLines(); 

// draw lines...

这更好吗? 然后出现的问题是:我应该在内部存储getHoughLines()的结果(即lines),还是应该直接将其返回给调用者?

4 个答案:

答案 0 :(得分:2)

我可以使用一些例子:

public class Multiplier {
    private int number;

    public Multiplier(int number) {
        this.number = number;
    }

    public int multiply(int other) {
        return number * other;
    }
} 

此类可以实例化为:

Multiplier multiplyByTwo = new Multiplier(2);

我可以使用它将列表中的许多元素乘以2。

但我可能需要乘以数字对。所以下面的课程可能就是我所需要的:

public class Multiplier {       
    public static int multiply(int number, int other) {
        return number * other;
    }
}

我可以将它设为静态,因为不需要任何状态。

此示例可以在列表中使用:

for (int x:listOfInts) {
    print(Multiplier.multiply(x * 2));
}

但可能在这个具体案例中,第一个例子更好。

for (int x:listOfInts) {
    print(multiplyByTwo(x));
}

甚至更好地用于Java 8''''

如果我需要在代码中的许多点获取乘法元素和结果,我可以这样做。

class Multiplier {
    private int x;
    private int y;

    public int multiply() {
        return x * y;
    }
    // getters and setters for x and y
}

在最后一种情况下,我可能会考虑不添加setter并在构造函数中传递x,y。

每种结构都可以用于某些特定情况。

答案 1 :(得分:2)

这不完全是个人风格的问题。但是,我认为这个话题可能有点争议(基于意见),因此不适合Q / A网站。

然而,显而易见的问题是:相应类的对象是否真的带有状态?也就是说,实例所代表的状态是否有任何好处?如果实例的唯一目的是使用一系列set...调用和最后调用execute()方法修改的变量的累加器,那么通常没有真正的理由实例 - 除了避免使用带有“many”参数的静态方法。

我认为静态方法的优点超过了调用具有“许多”参数的方法的大多数潜在笨拙。其中一个最重要的可能是使用静态方法的方法不会增加状态空间。每个字段都是状态空间中的另一个维度,并且正确记录状态空间可能很难。静态方法强制执行更“功能”的编程风格:它们没有任何副作用,因此是线程安全的(这变得越来越重要)。

(注意:所有这些都是指与任何静态状态相关的静态方法 - 无论如何都应该避免。当然,这是指方法,不涉及或针对与多态性相关的任何事情)。

毕竟,人们可以从任何地方轻松调用任何静态方法 - 甚至可以在实例方法中调用,并将某些字段作为参数传递。相反的情况并不那么容易:当你想调用一个依赖于许多实例字段的方法时,首先必须创建一个对象并适当地设置字段(仍然不知道它是否处于有效状态)可能会很麻烦调用方法)。我还看到Java 8的default方法作为一个很好的应用案例,其中静态实用程序方法派上用场:default方法可以轻松委托给实用程序方法,因为不涉及任何状态。

答案 2 :(得分:1)

何时不使用静电:

如果要返回的结果取决于构成你的"计算的其他变量(状态)"类然后静态不能使用。

但是,如果您只是对变量进行计算,如示例所示,静态可能是要采用的方式,因为它需要更少的代码(例如,通过第一种方法对变量执行calc1然后calc2)必须这样做:

 calculation calc =  new calculation(x)
 calc.calc1();
 calc.calc2();
 XYZ y = calc.getBla();

虽然你可以做第二个例子

 static import ...calculation.*;
 ...
 XYZ y = calc2(calc1(x));

答案 3 :(得分:1)

我选择第一个选项有几个原因,即状态超过静态函数的对象,特别是对于复杂的计算,但也适用于更简单的计算。

  1. 对象可以更好地用于命令模式。
  2. 对象更适合策略模式。
  3. 静态方法可以将单元测试变成噩梦。
  4. 静态是OOP中的反模式,因为它打破了多态性,相关技术的副作用会破坏它,例如:打开/关闭,模拟,代理等。
  5. 至少这是我的2c。

    你的第一个例子的奇怪部分是那些calcX方法没有说明幂等性,所以不清楚当它被操纵时this.bla是什么。对于具有可选设置的复杂计算,另一种方法是使用构建器模式构造不可变对象,然后提供基于固定对象状态和参数返回结果的calcX方法。但这种适用性实际上取决于用例,所以YMMV。

    更新:使用新代码,更多OOP方法是装饰Mat。支持委托而不是继承,你会得到像

    这样的东西
    public class MyMat
    {
        private Mat i;
    
        public MyMat(Mat i) {
           this.i = i;
        }
    
        public Mat getBackingMat() {
           return this.i;
        }
    
        public MyMat cannyEdges(int low, int high)
        {      
            // ...
            return new MyMat(I); // lets you chain operations
        }
    
        public MyMat cannyEdges()
        {
            return new MyMat(ImageProcessing.cannyEdges(I, ContourDetection.CANNY_LOWTHRES, ContourDetection.CANNY_HIGHTHRES));
        }
    
        public MyMat getHoughLines(...some_conf_vars...)
        {
            // ...
        }
    }
    
    MyMat myMat = new MyMat(I);
    lines = myMat.cannyEdges(20, 100).calcHoughLines();
    

    这只是猜测,因为我不知道那些东西是什么意思。 :)