Мне часто бывает трудно решить, какой из этих двух способов использовать, когда мне нужно использовать общие данные для некоторых методов в моих классах. Что будет лучшим выбором?
В этом варианте я могу создать переменную экземпляра, чтобы избежать необходимости объявлять дополнительные переменные, а также избежать определения параметров метода, но может быть не очень понятно, где эти переменные создаются / модифицируются:
public class MyClass {
private int var1;
MyClass(){
doSomething();
doSomethingElse();
doMoreStuff();
}
private void doSomething(){
var1 = 2;
}
private void doSomethingElse(){
int var2 = var1 + 1;
}
private void doMoreStuff(){
int var3 = var1 - 1;
}
}
Или просто создание экземпляров локальных переменных и передача их в качестве аргументов?
public class MyClass {
MyClass(){
int var1 = doSomething();
doSomethingElse(var1);
doMoreStuff(var1);
}
private int doSomething(){
int var = 2;
return var;
}
private void doSomethingElse(int var){
int var2 = var + 1;
}
private void doMoreStuff(int var){
int var3 = var - 1;
}
}
Если ответ заключается в том, что они оба верны, то какой виден / используется чаще? Кроме того, если вы можете предоставить дополнительные плюсы / минусы для каждого варианта будет очень ценным.
java
coding-style
carlossierra
источник
источник
Ответы:
Я удивлен, что это еще не упоминалось ...
Это зависит , если
var1
это на самом деле часть вашего объекта состояния .Вы предполагаете, что оба эти подхода верны и это просто вопрос стиля. Вы неправы.
Это полностью о том, как правильно моделировать.
Точно так же
private
существуют методы экземпляра для изменения состояния вашего объекта . Если это не то, что делает ваш метод, то так и должно бытьprivate static
.источник
transient
не имеет к этому никакого отношения, потому чтоtransient
речь идет о постоянном состоянии, как в частях объекта, которые сохраняются, когда вы делаете что-то вроде сериализации объекта. Например, хранилище резервных копий ArrayList являетсяtransient
важным, хотя и крайне важным для состояния ArrayList, потому что при сериализации ArrayList вы хотите сохранить только ту часть резервного хранилища, которая содержит фактические элементы ArrayList, а не свободное пространство. в конце зарезервировано для дальнейшего добавления элемента.var1
это необходимо для пары методов, но не является частью состоянияMyClass
, возможно, пришло время поместитьvar1
эти методы в другой класс, который будет использоватьсяMyClass
.Я не знаю, какая из них более распространена, но я бы всегда делал последнее. Он более четко связывает поток данных и время жизни, и он не переполняет каждый экземпляр вашего класса полем, единственное релевантное время жизни которого - во время инициализации. Я бы сказал, что первое просто сбивает с толку и значительно усложняет проверку кода, поскольку я должен учитывать возможность изменения любого метода
var1
.источник
Вы должны максимально уменьшить область действия ваших переменных (и разумно). Не только в методах, но и вообще.
Для вашего вопроса это означает, что это зависит от того, является ли переменная частью состояния объекта. Если да, то можно использовать его в этой области, то есть для всего объекта. В этом случае перейдите с первым вариантом. Если нет, воспользуйтесь вторым вариантом, так как он уменьшает видимость переменных и, следовательно, общую сложность.
источник
Есть другой стиль - используйте контекст / состояние.
У этого подхода есть ряд преимуществ. Например, объекты состояния могут изменяться независимо от объекта, что дает много возможностей для будущего.
Это шаблон, который также хорошо работает в распределенной / серверной системе, где некоторые детали должны сохраняться при вызовах. Вы можете хранить данные пользователя, соединения с базой данных и т. Д. В
state
объекте.источник
Это о побочных эффектах.
Вопрос о том,
var1
является ли часть государства, упускает смысл этого вопроса. Конечно, еслиvar1
должно сохраняться, это должен быть экземпляр. Любой подход может быть использован для работы, независимо от того, нужно упорство или нет.Побочный эффект подхода
Некоторые переменные экземпляра используются только для связи между закрытыми методами от вызова к вызову. Этот тип переменной экземпляра может быть реорганизован из существования, но это не обязательно. Иногда с ними все становится понятнее. Но это не без риска.
Вы выпускаете переменную из области видимости, потому что она используется в двух разных частных областях. Не потому, что это нужно в том объеме, в котором вы его размещаете. Это может сбивать с толку. «Глобалы злые!» уровень запутанности. Это может сработать, но это не будет хорошо масштабироваться. Работает только в малом. Нет больших объектов. Нет длинных цепочек наследования. Не вызывайте эффекта йо-йо .
Функциональный подход
Теперь, даже если
var1
должно сохраняться, ничто не говорит о том, что вы должны использовать if для каждого переходного значения, которое оно может принять, прежде чем достигнет состояния, которое вы хотите сохранить между публичными вызовами. Это означает, что вы все равно можете установитьvar1
экземпляр, используя только более функциональные методы.Так что часть государства или нет, вы все равно можете использовать любой подход.
В этих примерах 'var1' не содержит ничего, кроме того, что ваш отладчик знает, что он существует. Я предполагаю, что вы сделали это сознательно, потому что вы не хотите предвзятого отношения к нам. К счастью, мне все равно, какие.
Риск побочных эффектов
Тем не менее, я знаю, откуда твой вопрос. Я работал под жалкой йо йо «ИНГ наследство , которое мутирует переменной экземпляра на нескольких уровнях , в нескольких методов и ушел беличьей пытается следовать за ним. Это риск.
Это боль, которая побуждает меня к более функциональному подходу. Метод может документировать свои зависимости и выводить в своей подписи. Это мощный, четкий подход. Это также позволяет вам изменить то, что вы передаете приватному методу, делая его более пригодным для повторного использования в классе.
Побочные эффекты
Это также ограничивает. Чистые функции не имеют побочных эффектов. Это может быть хорошо, но это не объектно-ориентированный. Большая часть объектной ориентации - это способность ссылаться на контекст вне метода. Делать это, не пропуская глобалы повсюду - это сила ООП. Я получаю гибкость глобального, но это приятно содержится в классе. Я могу вызвать один метод и мутировать каждую переменную экземпляра сразу, если мне нравится. Если я сделаю это, я обязан, по крайней мере, дать методу имя, которое прояснит, к чему он стремится, чтобы люди не удивились, когда это произойдет. Комментарии также могут помочь. Иногда эти комментарии оформляются как «условия публикации».
Недостаток функциональных частных методов
Функциональный подход проясняет некоторые зависимости. Если вы не используете чисто функциональный язык, он не может исключать скрытые зависимости. Вы не знаете, глядя только на сигнатуру метода, что она не скрывает побочный эффект от вас в остальной части кода. Вы просто не
Пост условия
Если вы и все остальные члены команды надежно документируете побочные эффекты (условия до / после) в комментариях, то выигрыш от функционального подхода намного меньше. Да, я знаю, мечтай.
Вывод
Лично я склоняюсь к функциональным закрытым методам в любом случае, если могу, но, честно говоря, это в основном потому, что эти комментарии до / после условного побочного эффекта не вызывают ошибок компилятора, когда они устарели или когда методы вызываются не по порядку. Если мне действительно не нужна гибкость побочных эффектов, я бы просто знал, что все работает.
источник
var1
в качестве переменной состояния путем изменения парадигм. Область видимости класса не просто где хранится состояние. Это также ограничивающая область. Это означает, что есть две возможные причины для размещения переменной на уровне класса. Вы можете утверждать, что делаете это только для охватывающей области, а не государство - зло, но я говорю, что это компромисс с артерией, которая также является злом. Я знаю это, потому что я должен был поддерживать код, который делает это. Некоторые были сделаны хорошо. Некоторым был кошмар. Граница между ними не государственная. Это читабельность.Первый вариант выглядит неинтуитивным и потенциально опасным для меня (представьте, по какой-то причине кто-то делает ваш приватный метод публичным).
Я бы предпочел создавать экземпляры ваших переменных при построении класса или передавать их в качестве аргументов. Последний дает вам возможность использовать функциональные идиомы и не полагаться на состояние содержащего объекта.
источник
Уже есть ответы, говорящие о состоянии объекта и о том, когда предпочтительнее второй метод. Я просто хочу добавить один общий вариант использования для первого шаблона.
Первый шаблон совершенно допустим, когда все, что делает ваш класс, - это то, что он инкапсулирует алгоритм . Одним из вариантов использования этого является то, что если вы записали алгоритм для одного метода, он будет слишком большим. Таким образом, вы разбиваете его на более мелкие методы, делаете его классом и делаете вложенные методы приватными.
Теперь передача всех состояний алгоритма через параметры может стать утомительной, поэтому вы используете приватные поля. Это также согласуется с правилом в первом абзаце, потому что это в основном состояние экземпляра. Вам нужно только иметь в виду и правильно задокументировать, что алгоритм не реентерабелен, если вы используете для этого закрытые поля . Это не должно быть проблемой в большинстве случаев, но это может вас укусить.
источник
Давайте попробуем пример, который делает что-то. Прости меня, так как это javascript, а не java. Дело должно быть таким же.
Посетите https://blockly-games.appspot.com/pond-duck?lang=en , перейдите на вкладку javascript и вставьте это:
Следует заметить , что
dir
,wid
иdis
не получают ходило много. Вы также должны заметить, что код в функции, котораяlock()
возвращает, очень похож на псевдокод. Ну, это актуальный код. Все же это очень легко читать. Мы могли бы добавить передачу и присваивание, но это добавило бы беспорядок, который вы никогда не увидите в псевдокоде.Если вы хотите доказать, что невыполнение присваивания и передачи - это нормально, потому что эти три переменные являются постоянным состоянием, тогда рассмотрите редизайн, который присваивает
dir
случайное значение каждому циклу. Не настойчиво сейчас, не так ли?Конечно, теперь мы могли бы
dir
перейти в область видимости сейчас, но не без необходимости загромождать наш псевдоподобный код с передачей и настройкой.Так что нет, государство не объясняет, почему вы решили использовать или не использовать побочные эффекты, а не передавать и возвращать. Также побочные эффекты сами по себе не означают, что ваш код не читается. Вы не получаете преимуществ чистого функционального кода . Но хорошо, с хорошими именами, их действительно приятно читать.
Нельзя сказать, что они не могут превратиться в спагетти, как кошмар. Но тогда, что не может?
Удачной охоты на уток.
источник