В основном мне нужно выполнять разные действия при определенных условиях. Существующий код написан таким образом
Базовый интерфейс
// DoSomething.java
interface DoSomething {
void letDoIt(String info);
}
Реализация первого рабочего класса
class DoItThisWay implements DoSomething {
...
}
Реализация второго рабочего класса
class DoItThatWay implements DoSomething {
...
}
Основной класс
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
worker = new DoItThisWay();
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
Этот код работает нормально и его легко понять.
Теперь, в связи с новым требованием, мне нужно передать новую информацию, которая имеет смысл DoItThisWay
.
Мой вопрос: хорош ли следующий стиль кодирования для удовлетворения этого требования.
Используйте новую переменную класса и метод
// Use new class variable and method
class DoItThisWay implements DoSomething {
private int quality;
DoSomething() {
quality = 0;
}
public void setQuality(int quality) {
this.quality = quality;
};
public void letDoIt(String info) {
if (quality > 50) { // make use of the new information
...
} else {
...
}
} ;
}
Если я делаю это таким образом, мне нужно внести соответствующие изменения в вызывающей стороне:
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
int quality = obtainQualityInfo();
DoItThisWay tmp = new DoItThisWay();
tmp.setQuality(quality)
worker = tmp;
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
Это хороший стиль кодирования? Или я могу просто бросить это
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
int quality = obtainQualityInfo();
worker = new DoItThisWay();
((DoItThisWay) worker).setQuality(quality)
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
java
coding-style
Энтони Конг
источник
источник
quality
в конструктор дляDoItThisWay
?DoItThisWay
иDoItThatWay
выполняется один раз в конструктореMain
.Main
это долгоживущий класс иdoingIt
вызывается много раз снова и снова.setQuality
метод будет вызываться несколько раз за время существованияDoItThisWay
объекта?Ответы:
Я предполагаю, что это
quality
должно быть установлено рядом с каждымletDoIt()
вызовом наDoItThisWay()
.Возникающая здесь проблема заключается в следующем: вы вводите временную связь (то есть, что произойдет, если вы забудете позвонить,
setQuality()
прежде чем вызыватьletDoIt()
наDoItThisWay
?). И реализации дляDoItThisWay
иDoItThatWay
расходятся (один должен былsetQuality()
позвонить, другой нет).Хотя это может не вызывать проблем прямо сейчас, оно может снова преследовать вас. Возможно, стоит взглянуть еще раз
letDoIt()
и подумать, может ли информация о качестве быть частью той, которуюinfo
вы проходите через нее; но это зависит от деталей.источник
С моей точки зрения ни одна из ваших версий не является. Во- первых , чтобы звонить ,
setQuality
прежде чемletDoIt
можно назвать это временное сцепление . Вы застряли, рассматриваяDoItThisWay
как производную отDoSomething
, но это не (по крайней мере, не функционально), это скорее что-то вродеЭто сделало бы
Main
что-то вродеС другой стороны, вы можете передать параметры классам напрямую (при условии, что это возможно) и делегировать решение, какое из них использовать фабрике (это сделает экземпляры взаимозаменяемыми, и оба могут быть получены из
DoSomething
). Это будетMain
выглядеть такЯ знаю, что вы написали, что
Но вы можете кэшировать детали, которые дорого создавать на фабрике, и передавать их конструктору.
источник
DoItThisWay
требует качества , чтобы быть установлен перед вызовомletDoIt
он ведет себя по- разному. Я ожидаю, чтоDoSomething
будет работать одинаково (не устанавливая качество раньше) для всех производных. Имеет ли это смысл? Конечно, это немного размыто, так как если бы мы вызывалиsetQuality
метод фабрики, клиент не знал бы, нужно ли устанавливать качество или нет.letDoIt()
(без какой-либо дополнительной информации) «Я могу правильно выполнить (делать все, что я делаю), если вы предоставите мнеString info
». ТребованиеsetQuality()
предварительного вызова усиливает предварительное условие вызоваletDoIt()
и, таким образом, будет нарушением LSP.letDoIt
" не будет выбрасывать какие-либо исключения, а если забыть вызвать "setQuality", то возникнетletDoIt
исключение, тогда я согласен, что такая реализация нарушит LSP. Но это выглядит как очень искусственные предположения для меня.Давайте предположим, что
quality
нельзя передать в конструктор, иsetQuality
требуется вызов .В настоящее время фрагмент кода, как
слишком мал, чтобы вкладывать в него слишком много мыслей. ИМХО это выглядит немного некрасиво, но не очень сложно понять.
Проблемы возникают, когда такой фрагмент кода растет и из-за рефакторинга у вас получается что-то вроде
Теперь вы не сразу видите, верен ли этот код, и компилятор не скажет вам. Таким образом, введение временной переменной правильного типа и избежание приведения является более безопасным для типов без каких-либо дополнительных усилий.
Тем не менее, я бы на самом деле дал
tmp
лучшее имя:Такое именование помогает сделать неправильный код неправильным.
источник
DoItThisWay
получаются более конкретные параметры - в зависимости от того, что вы предлагаете, имя нужно менять каждый раз. Лучше использовать имена vor переменных, которые проясняют тип объекта, а не то, какие имена методов доступны.workerThisWay
стать чем-то вродеusingQuality
. В этом небольшом фрагменте кода безопаснее быть более конкретным. (И если в их домене есть фраза лучше, чем «usingQuality», используйте ее.Общий интерфейс, где инициализация изменяется в зависимости от данных времени выполнения, обычно поддается фабричной схеме.
Затем DoThingsFactory может беспокоиться о получении и установке информации о качестве внутри
getDoer(info)
метода перед возвратом конкретного объекта DoThingsWithQuality, приведенного к интерфейсу DoSomething.источник