Интерфейс с двумя различными реализациями - PullRequest
7 голосов
/ 16 августа 2011

У меня есть интерфейс Person, и у меня есть 2 класса Female и Male, которые реализуют интерфейс.

Для класса для женщин у меня есть метод getPregnancyMonth, которого нет в моем классе для мужчин. Добавление этого метода в мой интерфейс Person становится проблемой, поскольку мой класс Male теперь должен наследовать этот метод от интерфейса; но мужчина никогда не будет беременным.

Каким было бы решение, мне нужно extend Человеку вместо implement?

РЕДАКТИРОВАТЬ: Извините, если мой вопрос не был ясным. В этом случае я добавил в интерфейс оба метода get / set из классов Male и Female.

    static void Main(Form form) {
        Person person = Factory.createPerson(form.getGender());
        person.setName(form.getName());

        if ("F".equals(gender)) {
            person.setPregnancyMonth(form.getPregnancyMonth());
        }
    }

У меня такой вопрос, так как мой интерфейс имеет getPregnancyMonth, мой мужчина должен добавить этот метод в конкретный класс для реализации интерфейса. Есть ли способ избежать этого?

Ответы [ 6 ]

5 голосов
/ 16 августа 2011

getPregnancyMonth Не должно быть в интерфейсе Person.

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

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

3 голосов
/ 16 августа 2011

Нет необходимости перемещать этот метод в интерфейс Person. Основная хитрость заключается в том, что когда приходит время выполнить getPregnancyMonth(), вы должны убедиться, что имеете дело с экземпляром Female, а не просто с экземпляром Person.

Например, если вам нужно обработать кучу Person объектов, которые не требуют какой-либо особой обработки, можно легко создать метод для этого:

public static void processPeople(List<Person> people) {
    for (Person p : people) {
        p.someMethod();
    }
}

Однако, когда вы должны иметь дело с методом getPregenancyMonth(), вы должны убедиться, что ваш метод принимает только Female экземпляров:

public static void checkBirthSchedule(Female girl) {
    girl.getPregnancyMonth();
    ...
}

Другими словами, когда вы пытаетесь достичь этого, держите вещи как можно более абстрактными в интерфейсах более высокого уровня, но при необходимости переходите к более конкретному типу. Использование такой техники, как создание отдельного метода с более конкретным типом Person, спасает вас во время компиляции от получения ClassCastException, что очень хорошо.

2 голосов
/ 16 августа 2011

На мой взгляд, getPregnancyMonth недостаточно универсален, чтобы быть в интерфейсе Person.Вероятно, он должен быть определен только в классе Female.

Вы также можете определить второй интерфейс, содержащий это getPregnancyMonth.Женщина будет реализовывать оба.

1 голос
/ 16 августа 2011

Не добавляйте getPregnancyMonth к Person. Как вы обнаружили, это не имеет особого смысла.

В объектно-ориентированном программировании базовый класс / интерфейс должен (в идеале) содержать только те детали, которые являются общими для каждого из его подклассов - поскольку getPregnancyMonth не является общим для обоих подклассов (это не имеет никакого смысла для Male), оно не должно быть в интерфейсе Person. Еще раз подчеркиваю - речь идет об идеалах.

Как и предлагали другие ответы, постарайтесь вообще избежать этой проблемы, если можете. Например, вы можете использовать instanceof, чтобы определить, является ли данный Person Male или Female, и вызывать getPregnancyMonth, только если Person является Female.

Редактировать , в ответ на комментарий: использование описанного фабричного метода в значительной степени бессмысленно. Если мы игнорируем тех людей, которые не хотят, чтобы их называли «нормальным» полом, вы когда-либо создадите объект Male или Female - вам гораздо лучше просто иметь public static Female createFemale ( ) и public static Male createMale ( ) методы в вашем Factory. Таким образом, вы избежите всех этой проблемы, с которой вы столкнулись. Это также избавит от строки, используемой как enum (то есть "male" или "female" в качестве аргумента getPerson), но это совсем другое дело ...

Если вы все еще хотите использовать комбинированный фабричный метод, вы можете привести результат как Female:

Female female = (Female) Factory.getPerson("female");
female.getPregnancyMonth ( );

Или, если у вас есть Person, который может быть или не быть Female, вы также можете разыграть его:

if (person instanceof Female)
{
    Female female = (Female) person;

    female.getPregnancyMonth( );
}

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

1 голос
/ 16 августа 2011

Реализация / расширение не имеет значения здесь.Вы можете либо заставить isPregnant () всегда возвращать false для Male, либо вы можете просто вставить метод непосредственно в Female.Если вы считаете, что смешно, что мужчина беременен, вы должны разработать свой код так, чтобы он вызывал isPregnant () только для женщины, а не для любого человека.

КСТАТИ. Под этим я не подразумеваю добавление if (от лица женщины), разработайте вашу иерархию, чтобы избежать этого.

0 голосов
/ 16 августа 2011

Звучит как нарушенная иерархия объектов, но, как указано, вашему интерфейсу нужны два метода: isFemale () и getPregnancyMonth (). Затем Male.getPregnancyMonth () генерирует исключение UnsupportedOperationException. Лучшим подходом, вероятно, было бы разработать вашу модель так, чтобы мужчина никогда не мог быть поставлен в положение, где будет задан вопрос о его месяце беременности.

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