Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在抽象类中保存数据的最佳实践_Java_Initialization_Abstract Class - Fatal编程技术网

Java 在抽象类中保存数据的最佳实践

Java 在抽象类中保存数据的最佳实践,java,initialization,abstract-class,Java,Initialization,Abstract Class,因此,作为一个例子,假设我们有一个名为Question的抽象类,这个问题包含很多字符串,一个用于问题本身,一个用于答案,两个响应发布给用户,如果用户的问题是对的/错的 public abstract class Question { private final String question; private final String answer; private final String answerCorrect; private final String

因此,作为一个例子,假设我们有一个名为
Question
抽象类
,这个问题包含很多字符串,一个用于问题本身,一个用于答案,两个响应发布给用户,如果用户的问题是对的/错的

public abstract class Question {

    private final String question;
    private final String answer;
    private final String answerCorrect;
    private final String answerWrong;

}
我的问题是,初始化所有字符串的常用方法是什么?到目前为止,我已经编写了两个版本,它们都有各自的优点和缺点,我想知道,是否有某种“最佳编码实践”可以做到这一点


版本A
初始化构造函数中的所有内容

public abstract class Question {

    //...

    public Question(String question, String answer, String answerCorrect, String answerWrong) {

        this.question = question;
        this.answer = answer;
        this.answerCorrect = answerCorrect;
        this.answerWrong = answerWrong;

    }
}
这看起来很方便,我唯一的问题是用户不确定字符串的顺序

public class ExampleClass extends Question {

    public ExampleClass() {
        super("I think, that's the answer", "and that's the question", "answer wrong?", "answer right?");
    }

}

版本B
不要立即初始化,等待用户初始化

public abstract class Question {

    //...

    public Question() {

        this.question = "";
        this.answer = "";
        this.answerCorrect = "";
        this.answerWrong = "";

    }

    public void setQuestion(String question) {
        this.question = question;
    }

    //...
}
这使得初始化变量更容易,但是字符串不能再是
final
,也不能保证用户会初始化所有变量


我还考虑过让子类实现在
Question
的构造函数中调用的抽象方法来初始化所有字符串并使它们保持
final
,但这个版本对我来说太奇怪了

还有其他/更好的方法吗?我应该选择哪个版本?

提前感谢您的支持。

A版是最好的选择。但是,你是对的,如果你不告诉你的用户(我假设的其他开发人员)哪个参数是哪个,他们就无法知道在哪里键入什么

这是方便的地方

下面是一个例子:

/**
 * Create a new instance of Question given the following parameters:
 * 
 * @param  question This is the question
 * @param  answer This is the answer
 * @param  answerCorrect Whenever someone guesses correct, print this
 * @param  answerWrong Whenever someone guesses wrong, print this
 */
public Question(String question, String answer, String answerCorrect, String answerWrong) {

    this.question = question;
    this.answer = answer;
    this.answerCorrect = answerCorrect;
    this.answerWrong = answerWrong;

}

这可能太过分了,但我相信你可以在这里找个建筑工人

public class Question
{
    private final String question;
    private final String answer;
    private final String answerCorrect;
    private final String answerWrong;

    Question(QuestionBuilder builder) {
        this.question = builder.question;
        this.answer = builder.answer;
        this.answerCorrect = builder.answerCorrect;
        this.answerWrong = builder.answerWrong;
    }

    // public getters omitted to shorten answer

    @Override
    public String toString(){
        return String.format("question: '%s', answer: '%s', answerCorrect: '%s', answerWrong: '%s'", question, answer, answerCorrect, answerWrong);
    }

    public static void main(String[] args) {
        QuestionBuilder qb = new QuestionBuilder();
        qb = qb.question("This is the question").answer("This is the answer").answerCorrect("Correct answer").answerWrong("Wrong Answer");
        Question question = new Question(qb);
        System.out.println(question);
    }


    public static class QuestionBuilder{
        private String question;
        private String answer;
        private String answerCorrect;
        private String answerWrong;

        public QuestionBuilder question(String question) {
            this.question = question;
            return this;
        }

        public QuestionBuilder answer(String answer) {
            this.answer = answer;
            return this;
        }

        public QuestionBuilder answerCorrect(String answerCorrect) {
            this.answerCorrect = answerCorrect;
            return this;
        }

        public QuestionBuilder answerWrong(String answerWrong) {
            this.answerWrong = answerWrong;
            return this;
        }
    }
}
给出输出

问题:'这是问题',回答:'这是答案',回答正确:'正确答案',回答错误:'错误答案'


注意:我知道原来的问题是关于一个抽象类的。我使用了一个具体的类,因此我可以给出一个工作示例,尽管该解决方案可以适用于抽象类。

不要将属性(如
问题
)仅仅看作变量,而要想让类正确运行,就必须遵守它们的值限制。它们可以是空的吗?它们可以是空的吗?现在设计方法和构造函数,这样就不可能打破这些限制。您可能会发现,唯一可以做到这一点的方法是在构造函数(您的版本A)中设置初始值。您可能必须向构造函数和setter方法添加前置条件检查,如果传递给它们的值会导致限制被破坏,则这些方法会检查给定的值,并抛出合适的异常(
NullPointerException
IllegalArgumentException


也可以考虑在构造对象之后改变属性的值是否真的有意义。如果不是,那么属性不应该是setter,这使得版本B不可能

如果您的属性是
final
,并且您放置了一个
setter
@nachokk,那么您的代码将无法编译。我提到:“(…)字符串不能再是final了(…)”
我唯一的问题是,用户无法确定字符串的顺序。用户不调用构造函数,开发者调用。为了确保正确的顺序,你应该写一条评论。这不应妨碍您选择版本A。考虑到大多数IDE都有提供构造函数参数的弹出窗口,第一个的缺点是N/A(还要注意,这个“缺点”适用于几乎所有编写过的方法和构造函数)。如果您有额外的非最终成员“点数”,然后使用CTOR给它一个合理的“未定义”值。然后为它添加一个setter。在getter的文档中,说明“未定义”值是什么。例如“-1,如果尚未设置任何点”。这就是“正确命名参数”的用武之地;)从自己的经验来看:说明如果其中一个参数为null会发生什么,或者一般来说,您期望它们是什么。如果参数可以有单位,则始终添加单位。(比如“int time”-它是什么?秒?天?它可能是负数吗?@Fildor:我想用与felix fritz在问题中的名字相同的名字。这个评论是不是想补充我的答案?如果是,我同意。我个人更喜欢用
listCarBrands
btnCreateNewEntry
这样的名字来描述汽车品牌列表和一个按钮,其目的是分别创建一个新条目。通过这种方式,我可以快速获得所有按钮的概览,例如,如果我在首选IDE中键入
btn
并点击Ctrl+Space(自动完成建议)。是的,这是一种添加:)@Dukeling同意,构建器不会强制用户设置每个值,但OP的“版本B”解决方案也是如此。与“版本B”解决方案不同,我相信构建器提供了OP所需的不变性。我以前从未见过类似的东西,这很酷!我认为,如果开发人员决定不初始化所有内容,这与在版本A中将字符串设置为null是一样的,对吗?“我喜欢这个主意。”费利克斯弗里茨说得对。例如,如果仅调用
.answer(…)
方法,则剩余元素将是
null
,结果输出将是
question:“这是问题”,回答:“null”,回答:“null”,回答错误:“null”
我提供的示例应该编译并运行,以便您可以在调试器中轻松地使用它,以查看它在各种不同情况下的工作方式。如果变量不能为null(并且是最终变量),我是否应该立即抛出NullPointerException?@felixfritz Yes;为了澄清这一点,我修改了我的答案。这种方法要么让我