#java #oop
#java #ооп
Вопрос:
допустим, у меня есть интерфейс, как показано ниже
public interface ConditionChecker {
boolean isInCondition(Person p);
}
Я хочу создать новый класс, реализующий вышеупомянутый интерфейс, но мне нужно реализовать функцию с другим параметром
public class MacroConditionChecker implements ConditionChecker {
public boolean isInCondition(Person p, MacroView mv);
}
Две проблемы:
Первый: если я изменю подпись интерфейса на boolean isInCondition(Person p, MacroView mv);
, то мне нужно обновить все классы, реализующие ConditionChecker
Второе: я хочу, чтобы потребители ConditionChecker просто вызывали isInCondition как есть
Я думаю, это означает:
public class MacroConditionChecker implements ConditionChecker {
private static final MacroView mv;
public MacroConditionChecker(MacroView mv) {
this.mv = mv;
}
public boolean isInCondition(Person p){
// now i have access to MacroView
}
}
итак, единственное изменение, которое мне нужно, это внести в то время, когда я решаю использовать MACROC conditionchecker, и вызов isInCondition не изменяется
Я на правильном пути? или есть какой-то другой способ добиться этого?
или я должен выделить MacroView в качестве собственного интерфейса
public class MacroConditionChecker implements ConditionChecker implements MacroView
Комментарии:
1. Это действительно одно из возможных решений. Но тогда он имеет ненужный вид постоянного состояния.. Что, если вы просто создадите новый метод в интерфейсе, который вызывает перегруженный метод с квалификатором по умолчанию?
2. Ваше первое решение довольно хорошее. Но почему вы объявили
mv
поле как статическое?3. @YassinHajaj не могли бы вы подробнее рассказать? не на 100% соответствует
4. Вы передаете несколько
ConditionChecker
классов в функцию, а затем выполняете цикл над ними, вызываяisInCondition
, чтобы проверить все условия сразу? Это объясняет ваше желание не менять этот интерфейс. Итак, я думаю, что ваше решение работает хорошо.
Ответ №1:
ConditionChecker
напоминает Command
шаблон проектирования. Комментарий со связанной страницы:
Команда отделяет объект, который вызывает операцию, от объекта, который знает, как ее выполнить. Для достижения такого разделения разработчик создает абстрактный базовый класс, который сопоставляет приемник (объект) с действием (указатель на функцию-член). Базовый класс содержит метод execute(), который просто вызывает действие на получателе.
Это именно то, что вам нужно. В случае, если вам нужно проверить только внутреннее состояние Person
объекта, этого достаточно. Если вы хотите проверить Person
объект с помощью external API
, то можно создать реализацию, которая связывает external API
в конструкторе с Person
объектом в методе. Простой пример:
import java.util.ArrayList;
import java.util.List;
public class DesignPatterns {
public static void main(String[] args) {
List<ConditionChecker> checkers = new ArrayList<>();
checkers.add(person -> person != null);
checkers.add(person -> person.getName() != null);
checkers.add(person -> person.getName().length() > 0);
checkers.add(new MacroViewConditionChecker(new MacroView()));
checkers.add(new RestApiConditionChecker(new RestApi()));
Person person = new Person();
person.setName("Name");
for (ConditionChecker checker : checkers) {
System.out.println(checker.isInCondition(person));
}
}
}
interface ConditionChecker {
boolean isInCondition(Person person);
}
class MacroViewConditionChecker implements ConditionChecker {
private final MacroView macroView;
public MacroViewConditionChecker(MacroView macroView) {
this.macroView = macroView;
}
@Override
public boolean isInCondition(Person person) {
return macroView != null;
}
}
class MacroView {
}
class RestApiConditionChecker implements ConditionChecker {
private final RestApi restApi;
public RestApiConditionChecker(RestApi restApi) {
this.restApi = restApi;
}
@Override
public boolean isInCondition(Person person) {
return restApi.checkName(person.getName());
}
}
class RestApi {
public boolean checkName(String name) {
System.out.println("Validate name ...");
System.out.println(name " is valid");
return true;
}
}
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Вы можете использовать этот шаблон вместе с цепочкой ответственности. Этот подход не привязывает Person
объект к какой-либо реализации. Эта привязка выполняется в конкретной ConditionChecker
реализации, которую можно легко заменить.
Ответ №2:
Учитывая, что MacroConditionChecker
невозможно соблюдать ConditionChecker
подпись, тогда какой смысл ее внедрять?
Возможно, лучшим подходом является преобразование MacroConditionChecker
class
в interface
который расширяет ConditionChecker
interface MacroConditionChecker extends ConditionChecker {
boolean isInCondition(final Person person, final MacroView macroView);
}
А затем предоставьте стандартную / простую реализацию (или что вам нужно)
class SimpleMacroConditionChecker implements MacroConditionChecker {
public boolean isInCondition(final Person person, final MacroView macroView) {
...
}
}
Те, которым необходимо проверить условие с помощью MacroView
, просто примут MacroConditionChecker
public boolean check(final MacroConditionChecker checker) {
return checker.isInCondition(this.person, this.macroView);
}
Лично я рассматриваю их как две полностью разделенные interface
системы, но подход расширения все еще хорош.
Выбирайте осторожно, особенно если они будут использоваться во многих местах.
Комментарии:
1. я не думаю, что это решает вторую проблему, о которой я упоминал. допустим, у меня есть много объектов, использующих ConditionalChecker и вызывающих isInCondition. Если он использует MACROC Conditionchecker, мне теперь нужно пойти и внести изменения во все места, где isInCondition. И если я откатываю MACROC conditionchecker, мне нужно снова внести те же изменения. Я пытаюсь минимизировать, чтобы я мог легко заменить логику для проверки условий
2. @ealeon как я уже сказал, если кому-то нужен дополнительный MacroView для проверки, то он должен принять средство проверки макроусловий. Это наиболее идиоматичный и правильный подход. Так что да, вам придется провести рефакторинг
Ответ №3:
Поскольку интерфейс запрашивает у вас только реализацию данного метода, вы можете перегрузить метод желаемыми параметрами, и соответствующая реализация запустится при передаче дополнительного параметра.
public class MacroConditionChecker implements ConditionChecker {
boolean isInCondition(Person p) {};
public boolean isInCondition(Person p, MacroView mv) {};
}
Комментарии:
1. но это не решает вторую проблему, о которой я упоминал, что пользователям ConditionChecker теперь нужно вызывать с дополнительными параметрами. Например, если я решу, что i MACROC conditionchecker больше не используется по умолчанию, мне нужно обойти все места и внести изменения, чтобы он вызывался только с одним аргументом, верно?
2. Java достаточно умна, чтобы вызывать метод, соответствующий классу этого объекта, и использовать реализацию метода, соответствующую параметрам, которые передаются ему во время вызова. Что это сделает, так это просто позволит вам вызывать isInCondition для объектов MACROC Conditionchecker с двумя параметрами в качестве входных данных, это ничего не изменит за пределами класса и не повлияет на другие вызовы, которые используют только ‘Person’ в качестве входных данных.
3. «Что это сделает, так это просто позволит вам вызывать isInCondition для объектов MACROC conditionchecker с двумя параметрами в качестве входных данных» это именно то изменение, которого я пытаюсь избежать. Если у меня есть 1000 объектов, которые теперь хотят использовать MACROC Conditionchecker isInCondition, я не хочу вносить 1000 изменений
4. Это позволило бы вам избежать создания 1000 объектов и настройки MacroView для всех из них во время создания, а вместо этого создать один объект, который имеет дело с любым MacroView, который вы хотите проверить.
5. нет, если я хочу, чтобы MACROC conditionchecker был установлен по умолчанию, и чтобы потребители только подмножества ConditionChecker использовали другой ConditionChecker с одним параметром. дело в том, что мне не нужно вносить какие-либо изменения в потребителей ConditionChecker, нет?