Избежать случая переключения для чистых причин кодирования? [Дубликат]

Измените <view на <View, потому что view не находится в пустом представлении. Это для пользовательского представления, определенного через class attr, как показано ниже:

<view
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    class="com.your.package.YourCustomView" />

И вы получили

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference

из-за LayoutInflater пытается разобрать class attr:

LayoutInflater Исходный код

//...
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
        boolean ignoreThemeAttr) {
    if (name.equals("view")) { // line 724
        name = attrs.getAttributeValue(null, "class"); // line 725
    }

    // Apply a theme wrapper, if allowed and one is specified.
    if (!ignoreThemeAttr) {
        final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
        final int themeResId = ta.getResourceId(0, 0);
        if (themeResId != 0) {
            context = new ContextThemeWrapper(context, themeResId);
        }
        ta.recycle();
    }

    if (name.equals(TAG_1995)) { // line 738
        // Let's party like it's 1995!
        return new BlinkLayout(context, attrs);
    }
//...
  • В строке 724 он проверяет, что ваш тэг view и получает true
  • Вкл. строка 725 пытается получить класс через class attr и получает null
  • В строке 738 он пытается проверить тэг blink и получает сбой

Кроме того, есть любопытная вещь, разработчики Android добавили пасхальное яйцо, вы можете попробовать:

<view
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    class="blink">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Some text" />
</view>
26
задан skaffman 11 December 2010 в 15:00
поделиться

8 ответов

Переключатель подобен любой другой структуре управления. Есть места, где это лучшее / чистое решение, и многие другие места, где это совершенно неуместно.

В дизайне OO обычно считается предпочтительным в такой ситуации, как ваша, использовать разные типы сообщений / классы, которые наследуются от общего класса сообщений, а затем использовать перегруженные методы для «автоматически» различают разные типы.

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

Но это настоящая боль.

Оцените, есть ли опция дизайна, такая как перечисление, которое возможно в вашем решении. Если нет, просто используйте переключатель.

25
ответ дан Toby 17 August 2018 в 20:48
поделиться
  • 1
    Я предполагаю, что вы имели в виду динамический полиморфизм, а не статический полиморфизм ( перегруженные методы ) – Geek 17 March 2013 в 18:26
  • 2
    @Toby Можете ли вы прочесть этот оператор с примером: «затем прикрепите атрибут к каждому перечисляемому значению, которое позволит вам использовать generics или type-building для создания разных объектов подкласса Action, чтобы способ обработки перегрузки работал.» – beinghuman 14 September 2017 в 06:00
  • 3
    Да, я бы, вероятно, просто сделал PlayerAction enum с public static PlayerAction forActionId(int actionId), а enum будет иметь общедоступный метод типа doAction. Нет необходимости в коммутаторе, просто PlayerAction.forActionId(number).doAction(args);. Теперь все, что вам нужно сделать, чтобы добавить другое действие, это добавить значение перечисления и реализовать на нем метод doAction. ПРИМЕЧАНИЕ. Мне не нравится использовать «порядковый номер». либо, так как легко переупорядочить ваши значения перечисления в алфавитном порядке и сломать что угодно, используя старые цифры. – Shadow Man 29 March 2018 в 23:40

Я не покупаю его. Кажется, что у этих фанатиков ООП есть машины, у которых есть бесконечная оперативная память и потрясающая производительность. Очевидно, что при использовании inifinite RAM вам не нужно беспокоиться о фрагментации ОЗУ и о влиянии производительности, которое возникает при непрерывном создании и уничтожении небольших вспомогательных классов. Перефразируя цитату из книги «Красивый код» - «Каждая проблема в информатике может быть решена с еще одним уровнем абстракции»

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

1
ответ дан James 17 August 2018 в 20:48
поделиться
  • 1
    Вы должны реорганизовать, а затем оптимизировать. Делать это наоборот не имеет никакого смысла. – Eva 27 January 2013 в 22:30

Я помещал сообщения в массив, а затем сопоставлял элемент с ключом решения, чтобы отобразить сообщение.

3
ответ дан Michael Swierzbinski II 17 August 2018 в 20:48
поделиться
  • 1
    не все должно быть ООП. Очень нравится этот ответ. – grasshopper 7 February 2014 в 11:57

На ум приходит Strategy .

Шаблон стратегии предназначен для предоставления средства для определения семейства алгоритмов, инкапсулирования каждого из них в качестве объект и сделать их взаимозаменяемыми.

В этом случае «семейство алгоритмов» - это ваши разные действия.


Что касается операторов switch - в «Чистом коде» Роберт Мартин говорит, что он пытается ограничить себя одним оператором switch для каждого типа. Не исключать их вообще.

Причина в том, что операторы switch не придерживаются OCP .

15
ответ дан Oded 17 August 2018 в 20:48
поделиться

С точки зрения дизайна вы можете использовать Command Pattern для данного сценария. (См. http://en.wikipedia.org/wiki/Command_pattern ).

Если вы неоднократно повторяете использование операторов switch в парадигме ООП, это свидетельствует о том, что ваши классы могут быть плохо оформлены. Предположим, что у вас есть надлежащий дизайн супер и подклассов и много полиморфизма. Логика операторов switch должна обрабатываться подклассами.

Для получения дополнительной информации о том, как вы удаляете эти инструкции switch и вводите соответствующие подклассы, я рекомендую вам прочитать первую главу «Рефакторинг» Мартином Фаулер. Или вы можете найти похожие слайды здесь http://www1.informatik.uni-wuerzburg.de/database/courses/pi2_ss03_dir/RefactoringExampleSlides.pdf . (Слайд 44)

4
ответ дан TechTravelThink 17 August 2018 в 20:48
поделиться

Операторы «Bad» switch часто включают тип объекта (или что-то, что может быть типом объекта в другом проекте). Другими словами, жестко кодировать то, что может быть лучше обработано полиморфизмом. Другие типы операторов switch могут быть в порядке

Вам понадобится оператор switch, но только один. Когда вы получите сообщение, вызовите объект Factory для возврата объекта соответствующего подкласса Message (Move, Attack и т. Д.), Затем вызовите метод message-> doit () для выполнения работы.

означает, что если вы добавляете больше типов сообщений, необходимо изменить только заводский объект.

16
ответ дан The Archetypal Paul 17 August 2018 в 20:48
поделиться
  • 1
    Как насчет того, чтобы делать такие вещи, как Map<Class<?>, Thing>, это очень похоже на «выполнение переключателя на классах», но это, однако, принято как хорошая практика? – YoTengoUnLCD 20 June 2016 в 20:14

Использовать команды. Оберните действие в объект и пусть полиморфизм сделает для вас переключатель. В C ++ (shared_ptr - это просто указатель или ссылка на языке Java. Это позволяет динамическую отправку):

void GameServer::perform_action(shared_ptr<Action> op) {
    op->execute();
}

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

void BlueClient::play() {
    shared_ptr<Action> a;
    if( should_move() ) a = new Move(this, NORTHWEST);
    else if( should_attack() ) a = new Attack(this, EAST);
    else a = Wait(this);
    server.perform_action(a);
}
1
ответ дан wilhelmtell 17 August 2018 в 20:48
поделиться

Операторы IMO switch не являются bad , но их следует избегать, если это возможно. Одним из решений было бы использовать Map, где ключи являются командами, а значения Command - объектами с помощью метода execute(). Или List, если ваши команды являются числовыми и не имеют пробелов.

Однако, как правило, вы должны использовать switch заявления при реализации шаблонов проектирования; одним примером может быть использование шаблона цепочки ответственности для обработки команд, заданных любой командой «id» или «value». (Был также отмечен шаблон Strategy .) Однако в вашем случае вы также можете изучить шаблон Command .

В основном, в OOP, вы попытаетесь использовать другие решения, чем полагаться на блоки switch, которые используют парадигму процедурного программирования. Однако, когда и как использовать это - это ваше решение. Я лично часто использую блоки switch при использовании шаблона Factory и т. Д.


Определение организации кода:

  • a пакет представляет собой группу классов с когерентным API (ex: Collection API во многих фреймах)
  • класс представляет собой набор когерентных функциональных возможностей (например: класс Math ...
  • метод является функциональностью a , он должен делать только одно и только одно. (например: добавление элемента в список может потребовать, чтобы увеличить указанный список, и в этом случае add метод будет полагаться на другие методы для этого и не будет выполнять эту операцию сам, потому что это не контракт).

Поэтому, если ваш оператор switch выполняет различные операции, вы « нарушает » это определение, тогда как использование шаблона проектирования не соответствует каждой операции в собственном классе (это собственный набор функциональных возможностей).

2
ответ дан Yanick Rochon 17 August 2018 в 20:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: