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

         return piece;       
     }
}

我并不习惯于处理异常,因此我只是在扔它们,但是到处我使用一种使用该工厂的方法告诉我,我必须抛出像Throwable这样的例外。

例如,在我的一个课程中,我有一种使用使用工厂的方法实例化许多对象的方法。我可以通过抛出异常来使用该类中的方法,但是,如果我尝试将对该类的引用传递给另一个类,然后使用该方法,则该方法将无法使用。然后,它迫使我尝试抓住例外。

我可能不需要工厂,但似乎很有趣,我想尝试使用模式。我创建该工厂的原因是我有6个子类,我不想通过将我想要的子类的类型传递给该方法来实例化。

有帮助吗?

解决方案

您正在尝试反思性创建一个 Piece 目的。

Class.forName()ClassNotFoundException, , 尽管 Class.newInstance() 抛出InstantiationException,IllegalAccessException(因此,为什么需要投掷 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;       
    }
}

PS, ,未经测试,只是显示出更好的方法。

希望这可以帮助! :)

其他提示

两个都 @SuppressWarningsthrows Throwable 环警钟。看 有效的Java 由布洛克。

如果您不想声明抛出语句或在任何地方尝试/捕获块。

创建一个类并扩展 RuntimeException 课程或使用 RuntimeException 本身或相关 RuntimeException 扩展课程。

然后将try-Catch块放在根部(您的出厂类方法)上,并将抛入运行时异常类型的异常(以上之一,无论您选择哪个)。

但是,这实际上取决于您的需求。在某个时候,您仍然需要处理异常,否则您的应用程序会在运行时抛出异常,并且如果您不处理它们,则应用程序不会做期望的事情。

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

请记住,您仍然需要处理异常。这并不意味着这会很好。

需要将例外捕获到某个地方。如果我正确理解您有一个在该工厂周围包裹的课程,请说一个 FactoryWrapper. 。在代码中的某个地方,您使用该包装器类,并且可以抛出异常或捕获异常,因为您使用的方法可能在某个时候(可能在基类中)被try/Catch Block包围。另一个地方(您通过 FactoryWrapper 参考)可能是最后的手段(这不是一个好习惯,但可能是从未被称为的方法),需要抓住例外。

这只是为什么您不能在其他班级中抛出异常的原因。正如其他已经提到的那样,请尝试不使用反射,因为这要比其他选择要慢得多。

您可以为每种类型使用一个抽象工厂,然后使用一个工厂。阅读详情 这里这里 。希望这可以帮助。

编辑 :

这里 是一篇关于反思的有趣文章。它将给您一个何时使用它的想法。

我建议您努力在编写异常处理程序方面变得舒适。否则,您唯一的选择是用代码弄乱 throws 正如您已经看到的那样,声明变得令人讨厌并造成困难。

在这种情况下,您的方法的主体可以抛出两个检查的例外: ClassNotFoundException 来自 forname() 打电话,然后 InstantiationException 来自 newInstance() 称呼。

如何最佳处理这些取决于您的应用程序和偏好。正如另一个答案所建议的那样,一种选择是简单地抓住它们并抛出未选中的例外。如果您期望在应用程序完成后永远不会发生这些异常,这是明智的。这可能是我在这里采用的方法,因为如果发生这些异常中的任何一个,则可能表明配置错误。

但是,如果有理由认为这些例外情况可以合理地在正常使用中发生,那么您应该考虑如何处理它们。例如,如果用户将作品子类名称输入GUI(我知道,但仅仅是为了说明),则 ClassNotFoundException 由于这个名称很容易被拼写错误,因此变得更加可能。在这种情况下,允许该方法抛出该异常并要求呼叫者捕获和处理它可能是有意义的(例如,通过向用户提供一条消息,该消息不存在请求的类不存在)。

像您一样使用反射是不理想的。一旦您重命名作品课,并且客户通过了精心编码的完全合格的classNames,您的应用将破坏您的应用程序。 Elite Gent的建议避免了这个问题,但仍然要求客户知道具体类,这正是工厂模式试图隐藏的。我认为,一种更好的方法是使用枚举来表示零件类型,并让客户将其作为参数传递给您的工厂方法,或为每种类型创建单独的出厂方法(具有可行的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);
        }
    }
}

我在这里使一切都保持在这里,以保持示例独立。通常,字段,作品,抽象作品和rok将是顶级模型类,而曲目也将是顶级的。

我认为这是一个更好的方法,并避免了异常处理问题。

返回到这一点,您可以考虑几种方法(基于您的反思方法):

像您所做的那样投掷是不好的练习,因为它会将所有错误汇总在一起,并使对客户的错误处理非常繁琐且不透明。除非您没有其他选择,否则请勿这样做。

为所有检查异常,在您的方法上声明“抛出”。要确定这是否有效,请考虑客户是否应该知道并了解您要投掷的异常类型。在您的示例中,要创建Rook的客户是否应该知道并了解InstantiationException,IllegalAccessexception和ClassNotFoundException您的反射代码?在这种情况下可能不是。

将它们包裹在不需要被客户捕获的运行时例外。这并不总是一个好主意。您正在调用的代码抛出检查例外情况的事实通常是有原因的。在您的示例中,您进行了反思,这可能在许多方面出错(API声明LinkageError,ExceptioninitializerError,ClassNotFoundException,IllegalAccessexception,InstantiationException和SecurityException)。在运行时例外包装检查的异常并不能消除该问题。我认为这样做是“代码气味”。如果错误意味着无法恢复的系统故障,那么它可能是一个有效的选择,但是在大多数情况下,您希望更优雅地处理此类失败。

为完整的子系统提供自定义检查例外。例如,请参见Spring的org.springframework.dao.dataaccessexception,用于包装所有实现特定数据访问例外。这意味着客户将只需要捕获一种例外类型,并且可以弄清楚详细信息。在您的情况下,您可以创建一个检查的零件exception,并使用它来包装所有反射错误。这是一个有效的异常处理模式,但我认为对于您的作品,这可能有点笨拙。

返回null。您可以在代码中捕获所有异常,如果出现了NULL,则可以返回NULL。只需确保您的Javadoc清楚地表明了这一点。这种方法的缺点是客户可能必须检查各地的无效。

返回特定的错误类型。这是我一段时间以前在Java Core API中看到的一种怪异(非常面向对象的)方法(darn,不记得在哪里)。为此,您将创建额外的类型:

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. 。如果他们不这样做,那么当调用零件方法时,他们将遇到抛出的无pportedoperationException。有点沉重,但很明确。我不确定我会走这么远,但这仍然是一个有趣的主意。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top