Java: когда использовать атрибуты, когда использовать параметры метода?



Я попытался погуглить и поискать этот вопрос, но почему-то не смог найти ничего относящегося к нему. Мне интересно, есть ли руководство 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;
}
}


Я имею в виду, что вы можете поспорить за оба дела. Я вижу преимущества и, возможно, недостатки для обоих разных стилей, но почему-то я предпочитаю второй, пока не требуется слишком много аргументов/параметров. Конечно, если мне нужно много-много других атрибутов и т. д., тогда первый будет лучше, проще и т. д. потому что мне не нужно передавать так много параметров в метод...



Просто вопрос личного стиля?
Или как решиться на один подход?
Спасибо





EDIT : лучший пример: я CU в настоящее время делает много обработки изображений, и вопрос будет заключаться в том, хранить ли изображение внутренне в состоянии объекта или нет. В настоящее время я не делаю этого, потому что я использую статические методы, и psasing само изображение 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) внутри или я должен непосредственно вернуть его вызывающему!?

629   4  

4 ответов:

Есть несколько причин, по которым я бы выбрал первый вариант, т. е. объект с состоянием над статическими функциями, особенно для сложных вычислений, но и для более простых.

  1. объекты лучше работают для командного шаблона.
  2. объекты лучше работают для паттерна стратегии.
  3. Статические методы могут превратить модульные тесты в кошмар.
  4. статика является анти-паттерном в ООП, потому что она нарушает полиморфизм, с побочным эффектом, что связанные с ней методы будут разрушаться вместе с ним., например, открытые / закрытые, насмешливые, прокси и т. д.

Это мой 2С, по крайней мере.

Странная часть вашего первого примера заключается в том, что эти методы calcX ничего не говорят об идемпотенции, поэтому неясно, что такое this.bla, когда им манипулируют. Для сложных вычислений с необязательными настройками альтернативой является построение неизменяемого объекта с использованием шаблона компоновщика, а затем предложить методы calcX, которые возвращают результат на основе фиксированного состояния объекта и параметров. Но применимость это действительно зависит от случая использования, поэтому YMMV.

Update : С вашим новым кодом более ООП-подходом было бы украсить 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();
Это всего лишь догадка, потому что я понятия не имею, что все это значит. :)

Я могу привести несколько примеров:

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));
}
Но, вероятно, в данном конкретном случае 1-й пример был лучше.
for (int x:listOfInts) {
    print(multiplyByTwo(x));
}

Или еще приятнее использовать с Java 8 " map "

Если мне нужно получить элементы умножения и результат во многих точках моего кода, я могу это сделать.

class Multiplier {
    private int x;
    private int y;

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

В этом последнем случае я могу рассмотреть возможность не добавлять сеттеры и передать x, y в конструктор.

Каждая структура может быть использована в некоторых конкретных случаях.

Это не совсем вопрос личного стиля. Но тем не менее, я предполагаю, что эта тема может быть немного спорной (основанной на мнении) и поэтому не идеально подходит для сайта Q/A.

Однако очевиден вопрос: действительно ли объект соответствующего класса несет состояние ? То есть есть ли какая-то выгода в том, что государство представлено инстанцией? Если единственная цель экземпляра - быть аккумулятором переменных, которые модифицируются последовательностью set... вызовы и окончательный вызов метода execute(), то обычно нет никакого реального оправдания для такого экземпляра - за исключением избегания иметь статический метод с "многими" параметрами. Я думаю, что преимущества статических методов перевешивают большую часть потенциальной неуклюжести вызова метода с "многими" параметрами. Одним из наиболее важных из них, вероятно, является то, что подход со статическими методами не увеличивает пространство состояний . Каждое поле-это другое измерение в государстве. пространство, и документирование пространства состояний должным образом может быть трудно. Статические методы навязывают более" функциональный " стиль программирования: они не имеют побочных эффектов и, таким образом, потокобезопасны (что становится все более важным).

(Примечание: все это относится к статическим методам, которые не связаны с любым статическимсостоянием - этого следует избегать в любом случае. И, конечно же, это относится к методам, которые не участвуют или не нацелены на что-либо, связанное с полиморфизмом).

И, в конце концов, можно легко вызвать любой статический метод из любого места - даже из метода экземпляра, и передать в некоторых полях в качестве параметров. Обратное не так просто: когда вы хотите вызвать метод, который зависит от многих полей экземпляра, это может быть хлопотно, когда вы сначала должны создать объект и установить поля соответствующим образом (все еще не зная, находится ли он в допустимом состоянии для вызова метода). Я также рассматриваю методы default Java 8 как хороший пример приложения где пригодятся статические методы полезности: Метод default может легко делегировать метод полезности, потому что никакое состояние не участвует.

Когда не использовать статику:

Если результат, который будет возвращен, зависит от других переменных (состояния), которые составляют ваш класс "вычислений", то статика не может быть использована.

Однако, если вы просто выполняете вычисления над переменной, как следует из примера, статика, вероятно, является способом пойти, так как она требует меньше кода (например, чтобы выполнить calc1, а затем calc2 над переменной первым методом, который вы должны были бы сделать:

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

В то время как со вторым примером вы могли бы do

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

Comments

    Ничего не найдено.