#java #android #android-fragments #polymorphism #abstract-class
#java #Android #android-фрагменты #полиморфизм #абстрактный класс
Вопрос:
Я пытаюсь сделать следующее:
public abstract class MyBaseFragment extends Fragment {
private FloatingActionButton fab;
protected void initFab(View contentView, int resourceId) {
fab = (FloatingActionButton) contentView.findViewById(resourceId);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
launchDetailsDialogFragment(new Animal());
}
});
}
private void launchDetailsDialogFragment(Animal animal) {
//...
}
}
Ключевым моментом здесь является строка о создании нового Animal .
У меня есть разные виды животных — кошки, собаки и т.д. Страница о кошках, страница о собаках и т. Д., Все они будут расширять MyBaseFragment. Таким образом, нажатие кнопки FloatingActionButton на странице Cat приведет к выполнению функции, которая передает новый Cat() в DialogFragment, где вы можете редактировать его детали. То же самое для собак. Но каждая деталь DialogFragment немного отличается, поскольку кошки и собаки имеют разные свойства друг от друга, хотя они оба животные.
Однако я не знаю, как применить полиморфизм здесь. Прямо сейчас все, что знает MyBaseFragment, это то, что он создаст новое животное, но на самом деле я хочу, чтобы он создал новую кошку или новую собаку и т. Д., В зависимости от того, где я расширяю базовый фрагмент.
Как мне это сделать?
Комментарии:
1. Я предполагаю, что расширяемые классы знают, какое животное использовать, поэтому, когда они вызывают initFab(), почему они не передают требуемое животное?
2. @AshFrench На странице Cat, например, есть список cats. Вы нажимаете cat, вы можете редактировать его детали (инициализированные из базы данных). Но если вы нажмете кнопку добавить, откроется то же диалоговое окно с подробными сведениями, только с новым / свежим объектом Cat (поэтому все поля пустые). Я пытаюсь использовать абстрактный класс для реализации функций, общих для всех страниц, но он все равно должен иметь возможность запускать уникальные вещи в зависимости от ситуации.
3. хорошо, вы рассматривали возможность использования абстрактного метода, который возвращает Animal , который реализует каждый класс, тогда вы могли бы сделать
launchDetailsDialogFragment(getNewAnimal())
4. Я не понимаю, каким будет getNewAnimal(), где он будет реализован и как он узнает, какое животное получить?
5. в вашем абстрактном классе есть
abstract protected Animal getNewAnimal();
затем в вашейCatFragment extends MyBaseFragment
реализацииgetNewAnimal()
, где он возвращаетnew Cat()
и так далее для других классов
Ответ №1:
Просто сделайте вызываемый метод абстрактным, чтобы каждый конкретный класс заполнял свою собственную реализацию
public abstract class MyBaseFragment extends Fragment {
private FloatingActionButton fab;
protected void initFab(View contentView, int resourceId) {
fab = (FloatingActionButton) contentView.findViewById(resourceId);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
launchDetailsDialogFragment();
}
});
}
protected abstract void launchDetailsDialogFragment();
}
Комментарии:
1. Есть ли разница между высказыванием
private void launchDetailsDialogFragment()
иprivate abstract void launchDetailsDialogFragment();
?2. Если вы используете abstract, у вас не может быть реализации по умолчанию. Без абстрактного вы можете.
3. Но если вы просто вводите
private void launchDetailsDialogFragment();
, компилятор говорит, что в нем отсутствует тело4. методы @ArukaJ не являются абстрактными, а классы. Поскольку ваш класс уже является абстрактным, поэтому методы body не принимаются
5. У вас не может быть частного и абстрактного вместе
Ответ №2:
да, вы можете обрабатывать семейства объектов, используя шаблон «Посетитель»: https://en.wikipedia.org/wiki/Visitor_pattern
Ответ №3:
Сделать launchDetailsDialogFragment
абстрактный:
protected abstract void launchDetailsDialogFragment();
И реализуйте его в подклассах, как вы хотите.
Комментарии:
1. Есть ли разница между высказыванием
protected void launchDetailsDialogFragment()
иprotected abstract void launchDetailsDialogFragment();
? Или использовать private вместо protected?2. @ArukaJ да.
abstract
ключевое слово означает, что эта функция передает свою реализацию классам, которые расширят ваш базовый класс.3.
abstract
обязывает все дочерние классы реализовать этот метод. Безabstract
этого они просто не могли бы переопределить его и оставить его пустым.4. @m0skit0 Но без абстракции вам нужно было бы сделать что-то вроде
protected void someFunction() {}
, верно? И тогда вы можете сделать@Override
это из дочернего класса, если хотите его реализовать5. Правильно. Все зависит от того, хотите ли вы заставить дочерние классы реализовать метод или подойдет метод по умолчанию в родительском классе. Кстати
@Override
, в обоих случаях это необязательно (но рекомендуется).
Ответ №4:
Вы должны позволить конкретным реализациям MyBaseFragment решать, какое животное создавать при запуске фрагмента detail.Насколько я могу понять, абстрактный класс MyBaseFragment знает только, что должен быть detailfragment, который должен запускаться при событии щелчка fabbutton, он не знает о типе фрагмента, который должен быть запущен.Это будет решаться конкретной реализацией фрагмента. Итак, отметьте метод, ответственный за создание detailfragment, как защищенный абстрактный и переопределите их в конкретных реализациях для создания конкретного animal .