ОО: для реализации нового класса требуется дополнительный параметр - PullRequest
4 голосов
/ 22 марта 2019

скажем, у меня есть интерфейс, как показано ниже

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
    }
}

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

Я включенправильный путь?или есть еще способ сделать это?

или я должен выделить MacroView как его собственный интерфейс

public class MacroConditionChecker implements ConditionChecker implements MacroView

Ответы [ 3 ]

1 голос
/ 22 марта 2019

Поскольку интерфейс требует только реализации данного метода, вы можете перегрузить метод требуемыми параметрами, и соответствующая реализация будет запущена при передаче дополнительного параметра.

public class MacroConditionChecker implements ConditionChecker {
    boolean isInCondition(Person p) {};
    public boolean isInCondition(Person p, MacroView mv) {};
}
1 голос
/ 23 марта 2019

ConditionChecker напоминает Command шаблон дизайна . Комментарий со связанной страницы:

Команда отделяет объект, который вызывает операцию от одного который знает, как это сделать. Чтобы добиться этого разделения, дизайнер создает абстрактный базовый класс, который отображает получателя (объект) с действие (указатель на функцию-член). Базовый класс содержит Метод execute (), который просто вызывает действие на получателе.

Это именно то, что вам нужно. Если вам нужно проверить только внутреннее состояние объекта Person, этого достаточно. Когда вы хотите проверить Person объект с внешним API, все в порядке, чтобы создать реализацию, которая связывает внешний 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, которую можно легко заменить.

1 голос
/ 22 марта 2019

Учитывая, что MacroConditionChecker не может уважать сигнатуру ConditionChecker, то какой смысл ее реализовывать?

Может быть, лучший подход - преобразовать MacroConditionChecker class в interface, который extends 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 с, но подход к расширению все еще хорош.
Выбирайте осторожно, особенно если они будут использоваться во многих местах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...