Вопрос

class PieceFactory {     
     @SuppressWarnings("rawtypes")
     public Piece createPiece(String pieceType) throws Throwable{
        Class pieceClass = Class.forName(pieceType);
        Piece piece = (Piece) pieceClass.newInstance();

         return piece;       
     }
}

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

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

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

Это было полезно?

Решение

Вы пытаетесь отражать Piece объект.

Class.forName() броски ClassNotFoundException, пока Class.newInstance() бросает instantiationException, нелегалаксексекция (следовательно, почему вам нужно бросить Throwable.

Лучший способ создать объект через типы классов, вероятно, - выполнить следующее:

class PieceFactory {     

    public Piece createPiece(String pieceType) throws Throwable{
        Piece piece = null;

        if ("SubPiece1".equals(pieceType)) {
            piece = new SubPiece1();
        } else if ("SubPiece2".equals(pieceType)) {
            piece = new SubPiece2();
        }

        return piece;       
    }
}

Пса, это не проверено, просто показывает лучший способ сделать это.

Надеюсь это поможет! :)

Другие советы

Оба @SuppressWarnings а также throws Throwable Кольцевые сигналы тревоги. Видеть Эффективная ява Блоха.

Если вы не хотите объявлять операторы бросков или пытаться/поймать блок везде.

Создать класс и расширить RuntimeException класс или использование RuntimeException сам или связанный RuntimeException Расширение занятий.

Затем поместите блок Try-Catch в корень (ваши методы фабричного класса) и оберните исключения, добавленные в тип исключения времени выполнения (один из выше, в зависимости от того, что вы выберете).

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

try{ 
    "your code which throws exception" 
} catch(ThrownExceptionType e){ 
   throw new RuntimrException(e);
}

Помните, что вам все еще нужно справиться с исключением. Это не значит, что это будет работать хорошо.

Исключения должны быть где -то поймать. Если я правильно понял, у вас есть один класс, который обернут вокруг этой фабрики, скажем FactoryWrapper. Анкет Где -то в вашем коде вы используете этот класс обертки, и вы можете либо бросить свое исключение, либо поймать его, потому что метод, в котором вы используете его, вероятно, окружен в какой -то момент (вероятно, в базовом классе) блоком Try/Catch, пока Другое место (в которое вы передаете FactoryWrapper Ссылка), вероятно, является последним средством (это не хорошая практика, но это может быть метод, который никогда не называется), где необходимо поймать исключение.

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

Вы можете использовать одну абстрактную фабрику, а затем фабрику для каждого типа. Смотрите подробности здесь а также здесь Анкет Надеюсь это поможет.

РЕДАКТИРОВАТЬ :

Здесь интересная статья о размышлении. Это даст вам представление о том, когда его использовать.

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

В этом случае тело вашего метода может бросить два проверенных исключения: ClassNotFoundException от forname() позвонить, и InstantiationException от newInstance() вызов.

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

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

Использование отражения, как вы делаете, не идеально. Как только вы переименуете класс произведений, и клиенты проходят в твердом кодировании полностью квалифицированных классов, ваше приложение сломается. Предложение Elite Gents избегает этой проблемы, но все еще требует, чтобы клиенты знали конкретный класс, что именно то, что заводской шаблон пытается скрыть. На мой взгляд, лучшим подходом будет либо использовать перечисление для представления типов частей, и позволить клиенту передать это в качестве аргумента вашего фабричного метода, либо создать отдельные фабричные методы для каждого типа (с 6 типами, которые осуществимы).

Поскольку я все равно откладываю, вот пример подходящего оборудования:

import java.util.ArrayList;
import java.util.List;

class PieceFactoryExample {

    static enum PieceFactory {
        ROOK {
            Piece create() {
                return new Rook();
            }
        };
        abstract Piece create();
    }

    static class Field {
        char line;
        int row;

        public Field(char line, int row) {
            this.line = line;
            this.row = row;
        }

        public String toString() {
            return "" + line + row;
        }
    }

    static interface Piece {

        void moveTo(Field field);

        List<Field> possibleMoves();
    }

    static abstract class AbstractPiece implements Piece {

        Field field;

        public void moveTo(Field field) {
            this.field = field;
        }
    }

    static class Rook extends AbstractPiece {

        public List<Field> possibleMoves() {

            List<Field> moves = new ArrayList<Field>();
            for (char line = 'a'; line <= 'h'; line++) {
                if (line != field.line) {
                    moves.add(new Field(line, field.row));
                }
            }
            for (char row = 1; row <= 8; row++) {
                if (row != field.row) {
                    moves.add(new Field(field.line, row));
                }
            }
            return moves;
        }
    }

    public static void main(String[] args) {

        Piece pawn = PieceFactory.ROOK.create();
        Field field = new Field('c', 3);
        pawn.moveTo(field);
        List<Field> moves = pawn.possibleMoves();
        System.out.println("Possible moves from " + field);
        for (Field move : moves) {
            System.out.println(move);
        }
    }
}

Я сделал все статическое здесь, чтобы сохранить пример автономным. Обычно Field, Piece, AbstractPiece и Rook будут классами моделей верхнего уровня, а PieceFactory также будут верхним уровнем.

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

Возвращаясь к этому, есть несколько подходов, которые вы можете рассмотреть (на основе вашего подхода к отражению):

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

Объявите «бросает» на ваш метод для всех проверенных исключений. Чтобы решить, является ли это действительным, рассмотрите, должен ли клиент знать и понять тип исключения, который вы бросаете. В вашем примере клиент, который хочет создать ROOK, знать и понять инстанцию, нелегалаксексапс и ClassNotFoundException, брошенное вашим кодом отражения? Вероятно, не в этом случае.

Оберните их в исключение времени выполнения, которое не нужно быть пойманным клиентами. Это не всегда хорошая идея. Тот факт, что код, который вы звоните, бросает проверенные исключения, обычно имеет причину. В вашем примере вы делали размышления, и это может пойти не так во многих отношениях (API объявляет LinkageError, ExcliveInitializerRor, ClassNotFoundException, OlgalAccessException, InstantiationException и Security Exception). Обертывание проверенных исключений в исключении времени выполнения не делает эту проблему исчезнуть. Я рассматриваю это «запах кода». Если ошибка означает непреодолимый сбой системы, то это может быть действительным выбором, но в большинстве случаев вы хотели бы обработать такие сбои более изящно.

Бросьте исключение на заказ для полной подсистемы. См., Например, Spring's org.springframework.dao.dataaccessexception, который используется для обертывания всех исключений для доступа к данным. Это означает, что клиенты должны будут поймать только один тип исключения и могут выяснить детали, если им нужно. В вашем случае вы можете создать проверенное PiecreationException и использовать его, чтобы обернуть все ошибки отражения. Это действительный образец обработки исключений, но я думаю, что это может быть немного жестким для вашего PieceFactory.

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

Вернуть конкретный тип ошибки. Это отвратительный (очень ориентированный на объект) подход, который я увидел в ядре Java Core API где-то некоторое время назад (черт возьми, не могу вспомнить, где). Для этого вы создали бы дополнительный тип произведения:

class NullPiece implements Piece {
    public void moveTo(Field field) {
        throw new UnsupportedOperationException("The Piece could not be created");
    }
    public List<Field> possibleMoves() {
        throw new UnsupportedOperationException("The Piece could not be created");
    }
}

И вернуть экземпляр этого типа, когда возникает ошибка во время создания. Преимущество заключается в том, что он более самозакументирует, чем возврат простой нулевой стоимости, но клиенты, конечно, должны были бы проверить это, используя что-то вроде instanceof. Анкет Если они этого не сделают, то они встретятся с UnsupportedOperationException, брошенным при вызове методов произведения. Немного тяжелый, но очень явный. Я не уверен, что зашел бы так далеко, но это все еще интересная идея.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top