Best practice for saving data in abstract classes - java

So, just as an example, let's say we have an abstract class called Question, that question contains a lot of strings, one for the question itself, one for the answer and two responses posted to the user, if he got the question right / wrong.
public abstract class Question {
private final String question;
private final String answer;
private final String answerCorrect;
private final String answerWrong;
}
My question basically is, what would be a common way to initialize all of the strings? So far I've made up 2 versions on how to do it, they have their up- and downsides and I wanted to know, if there was some kind of "best coding practice" for this.
Version A
Initialize everything in the constructor.
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;
}
}
This seems pretty convenient, the only problem I have with this is that users will not be sure, in which order the strings have to be.
public class ExampleClass extends Question {
public ExampleClass() {
super("I think, that's the answer", "and that's the question", "answer wrong?", "answer right?");
}
}
Version B
Don't initialize instantly and wait for the user to do it.
public abstract class Question {
//...
public Question() {
this.question = "";
this.answer = "";
this.answerCorrect = "";
this.answerWrong = "";
}
public void setQuestion(String question) {
this.question = question;
}
//...
}
This makes it easier to initialize variables, but the Strings can't be final anymore and it's not guaranteed that the user will initialize all of them.
I've also thought about letting the child-class implement abstract methods that are called in the constructor of Question to initialize all the strings and to keep them final, but that version seemed a little too strange to me.
Are there other / better ways to do it? What version should I prefer?
Thanks in advance for your support.

Version A is the way to go. You're right, though, if you do not tell your users (the other developers I'm assuming) which parameter is which, there is no way for them to know where to type what.
This is where Javadoc comes in handy.
Here's an example:
/**
* 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;
}

This might be overkill, but I believe you could use a builder here...
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;
}
}
}
Gives the output
question: 'This is the question', answer: 'This is the answer', answerCorrect: 'Correct answer', answerWrong: 'Wrong Answer'
Note: I realize the original question was in reference to an abstract class. I used a concrete class so I could give a working example, although the solution can be adapted for use with an abstract class.

Instead of thinking of the attributes (such as question) as just variables, think of the restrictions on their values that must be obeyed for the classes to behave correctly. Can they be null? Can they be empty? Now design your methods and the constructor so it is impossible for those restrictions to be broken. You might find that the only way you can do this is to set initial values in the constructor (your version A). You might have to add pre-condition checks to your constructor and setter methods, which check the values given a throw a suitable exception (NullPointerException or IllegalArgumentException) if the values passed to them would result in the restrictions being broken.
Also, consider whether it really makes sense to change the value of an attribute after the object is constructed. If not, then the attribute should not a setter, making your version B impossible.

Related

Enums in Java VS Enums in C# [duplicate]

This question already has answers here:
C# vs Java Enum (for those new to C#)
(13 answers)
Is it possible to add custom properties to c# enum object?
(2 answers)
Closed 2 years ago.
I have a very basic question. In Java, it is possible to point attributes and variables to Enums, such as:
public enum DayTime{
Morning("Morning"),
Afternoon("Afternoon"),
Night("Night");
private string description;
Daytime(string description){
this.description = description;
}
public string getDescription(){
return description;
}
}
Is it possible to apply the same concept to C#? I am trying to get modular descriptions to products, whereas their name, contents and characteristics would be shown in a string of text, and Enums looked like the best alternative to modify this text according to which characteristic is selected.
C# enums are very basic compared to Java enums. If you want to simulate the same kind of behavior you need to use a class with an inner enum:
using System.Collections.Generic;
public sealed class DayTime
{
public static readonly DayTime Morning = new DayTime("Morning", InnerEnum.Morning);
public static readonly DayTime Afternoon = new DayTime("Afternoon", InnerEnum.Afternoon);
public static readonly DayTime Night = new DayTime("Night", InnerEnum.Night);
private static readonly List<DayTime> valueList = new List<DayTime>();
static DayTime()
{
valueList.Add(Morning);
valueList.Add(Afternoon);
valueList.Add(Night);
}
//the inner enum needs to be public for use in 'switch' blocks:
public enum InnerEnum
{
Morning,
Afternoon,
Night
}
public readonly InnerEnum innerEnumValue;
private readonly string nameValue;
private readonly int ordinalValue;
private static int nextOrdinal = 0;
private string description;
internal DayTime(string name, InnerEnum innerEnum)
{
this.description = name;
nameValue = name;
ordinalValue = nextOrdinal++;
innerEnumValue = innerEnum;
}
public string Description
{
get
{
return description;
}
}
//the following methods reproduce Java built-in enum functionality:
public static DayTime[] values()
{
return valueList.ToArray();
}
public int ordinal()
{
return ordinalValue;
}
public override string ToString()
{
return nameValue;
}
public static DayTime valueOf(string name)
{
foreach (DayTime enumInstance in DayTime.valueList)
{
if (enumInstance.nameValue == name)
{
return enumInstance;
}
}
throw new System.ArgumentException(name);
}
}
Given this complexity, it may be best to rewrite your logic in a way that's more natural for C# without using enums.

Arrays with getters and setters not getting result

I am trying to get to work getters and setters with arrays, I have created 2 objects Question and Answer with their get and setters. I have also created 2 arrays one called Question and one called Answer.
class Question {
private String[] questions;
public void setQuestion(String questions[]) {
this.questions = questions;
}
public String[] getQuestion() {
return questions;
}
}
class Answer {
private String[] answers;
public void setAnswer(String answers[]) {
this.answers = answers;
}
public String[] getAnswer() {
return answers;
}
}
But when trying to print the questions it does not recognise `getQuestion'
for (int n = 0; n<getQuestion.length; n++) {
System.out.println("Question" + (n+1));
System.out.println(getQuestion(Question[n]);
}
getQuestion is a method of your Question class and should be called like that, like questions.getQuestion(). Probably, you want to return a single question for getQuestion too?
You need to create an instance of the Question class then call the getQuestion() method.
Depending on what you are trying to do you may also need to make the Question class public using the public modifier
Note
You could also as Pavneet_Singh pointed out make the getQuestion() method static thus removing the need to create a new instance of the Question class.
Updated code
Question question = new Question();
for (int n = 0; n<question.getQuestion().length; n++) {
System.out.println("Question" + (n+1));
//note that this wont work, you dont pass any parameters to the getQuestion() method
System.out.println(getQuestion(Question[n]);
}
Some improvements to your code;
public class Question {
private String question;
//Use Question constructor to populate the question string
public Question( String question ){
this.question = question;
}
//get the question
public String getQuestion(){
return question;
}
}
//follow same pattern here
public class Answer {
private String answer;
public Answer( String answer ){
this.answer = answer;
}
public String getAnswer(){
return answer;
}
}
Main Method
//Create array of type Question
Question[] questions = new Question[3];
//create new questions and use constructor to set string question
Question question1 = new Question('What is your name?');
Question question2 = new Question('What is your age?');
Question question3 = new Question('What is your favourite color?');
//add questions to array
questions.add(question1);
questions.add(question2);
questions.add(question3);
int counter = 0;
//loop through the array
for (Question question : questions) {
System.out.println("Question " + (counter+1));
System.out.println(question.getQuestion();
counter++;
}
Ill let you figure out how to map questions to answers

Object becoming null outside return statements

this may be a simple problem, but I've looked for an answer and I'm just not finding it anywhere. I'm trying to use a method to check if an inputted answer is correct compared to the actual answer. The actual answer is defined by a setter, and the getter works also. But in the method where it's compared it becomes null. This isn't a question about why comparing them returns null, but why correctAnswer is null in the first place. I'm confused because getCorrectAnswer() works as intended.
Here is the code:
public class MultipleChoiceQuestion implements Question
{
String question;
String correctAnswer;
public String getQuestion()
{
return question;
}
public boolean isCorrectAnswer(String answer)
{
if (answer != correctAnswer)
{
return false;
}
return true;
}
public String getCorrectAnswer()
{
return correctAnswer;
}
public void setQuestion(String questionText){
question = questionText;
}
public void setAnswer(String answer){
correctAnswer = answer;
}
}
"answer != correctAnswer" doesn't work because correctAnswer is null in that method.
You shouldn’t use equality for classes unless you want to check that two are perfectly identical, that is, the same object. You should use Object.equals. So answer.equals(correctAnswer) is more correct. Also, are you sure that the setter was called first?

Proper Constructors to Run all Methods in Java

I have this class and need to know which constructor is needed to create an object that may immediately use all its methods without error
public class Robot {
private boolean fuelEmpty = true;
private int roboID;
private String greeting;
private String securityProtocol;
//insert robot constructor here
public void destroyAllHumans(){
while (fuelEmpty == false) {
//robot begins to destroy all humans
}
}
public int getRoboID(){
return roboID;
}
public void greet(){
System.out.println(greeting);
}
public void setSecurityProtocol(String proto){
securityProtocol = proto;
}
}
For example should look like this:
public Robot(int id, String greet) {
roboID = id;
greeting = greet;
}
or this:
public Robot(int id, String greet) {
roboID = id;
greeting = greet;
fuelEmpty = false;
}
or:
public Robot(boolean full, int id, String greet, String proto) {
roboID = id;
greeting = greet;
fuelEmpty = full;
securityProtocol = proto;
}
Which of these (or something else different) is needed so that all the other methods can run without an error?
You can overload the constructor as much as you need, the important thing is
the object gets properly instantiated after you create a new one...
a way can be:
public Robot() {
this(false, 0, "", "");
}
public Robot(int id) {
this(false, id, "", "");
}
public Robot(boolean fuelEmpty, int roboID, String greeting, String securityProtocol) {
this.fuelEmpty = fuelEmpty;
this.roboID = roboID;
this.greeting = greeting;
this.securityProtocol = securityProtocol;
}
so look how all other constructors will at the end call internally the
public Robot(boolean fuelEmpty, int roboID, String greeting, String securityProtocol)
that will give you the waranty that no matter which constructor is invoked, the Robot is fully created and can invoke all those methods without crashing
The solution works like this:
you look at each of your methods
you check which fields each method is using
you check more closely, if the method breaks when that field has its default value (like null for Objects, or false for booleans)
When you do that for all methods, you get a list of those fields that you need to initialize somehow. Then you could go forward and define a corresponding constructor.
But of course, that is the wrong approach.
The real answer goes like this: you don't put fields into a class because you can. You add them because they are required so that this class can implement the requirements (responsibilities) that you want it to implement. Meaning: you focus on the methods that your class should provide. Then you clarify which fields you need in order to implement these methods.
In other words: you have exactly those fields in your class that your class needs. If you have fields in there that go unused - then you get rid of them.

A real life example of public properties being bad

Countless times I've read that public properties on a class are a major faux pas, but I fail to see why on data that doesn't get transformed going in/out.
example of something I would write
public class Employee
{
public String firstName;
public String lastName;
private int ssn = 0;
public boolean setSsn(String s)
{
//makes perfect sense why something like an ssn would use a getter setter
//some code to validate ssn
if(!validSsn(s)){
ssn = 0;
return false;
}
ssn = raw;
return true;
}
public String getSsn()
{
return ssn;
}
private boolean validSsn(String s)
{
//validation goes here
retrun val;
}
//I don't understand why I should make firstName private
// and then write
public void setFirstName(String s)
{
firstName = s;
}
public String getFirstName(String s)
{
return firstName;
}
}
please provide a scenario in which this would cause a problem and please be specific, not "because it causes issues when other people use your code" WHY? Why does it cause issues. Thanks in advance for constructive criticism and detailed answers :D
Imagine that your code has gone to production. I write a front-end that uses your Employee class that accesses firstName and lastName directly.
6 months go by, and now there's a new business requirement that you add validation to the name fields.
Where are you going to add it? You're going to have to make the fields private and add set methods, and this will force me and everyone else using your code to re-write our apps.
If you had encapsulated that data properly in the first place, all we'd have to do is recompile using the new version of the library with your code.

Categories

Resources