2
\$\begingroup\$

I made a very simple program where you input a students grades (edit the code with the set method?) and the program will output the average. Each test has a different weight associated with it.

The problems I think I have right now are:

  1. I am not properly utilizing my methods. The getters and setters are probably done wrong.

  2. Should I make testScore1 its own class since a test can have a test score, test worth % (weight)?

  3. Is it good coding practice to use code separators to separate code for easier viewing?

Main question

  1. Should the declaring of a students name and grades be inside the student class or was I correct in setting them in the main method? (I think that a student's info (name and grades) should be kept inside the Student class and that the main method should be using get methods to access them rather than setting them. Is my thinking correct?)

The basis of what I am trying to achieve is the first comment in my code.

application class

/*
 * --- Student Grade Book Application ---
 * Keep track of students (with a student class that has their name,     average, and scores) in a class and their grades.
 * Assign their scores on tests and assignments to the students and figure     out their average and grade for the class.
 * For added complexity put the students on a bell curve.
 */

// I think this will require multidimensional arrays 
public class application {

public static void main(String[] args) {

    Student student1 = new Student();

    student1.setName("Bob"); // Should the name of the student be declared here with a setName?
    student1.setTestScore1(80);
    student1.setTestScore2(60);
    student1.setFinalExamScore(90);

    student1.calculateEntireAverage();
    System.out.println(student1.calculateEntireAverage() + "%");

}
}

Student class

public class Student{
private String name;
private double average;
private double testScore1; // worth 25% (should I make testScore1 it's own     class since a test can have a test score, test worth %)
private double testScore2; // worth 25%
private double finalExamScore; // worth 50%

// Getter for name
public String getName() {
    return name;
}

// Setter for name
public void setName(String name) {
    this.name = name;
}

// ----------------------------------------------------
// Getter for testScore1
public double getTestScore1() {
    return testScore1;
}

// Setter for testScore1
public void setTestScore1(double testScore1) {
    this.testScore1 = testScore1;
}


// Getter for testScore2
public double getTestScore2() {
    return testScore2;
}

// Setter for testScore2
public void setTestScore2(double testScore2) {
    this.testScore2 = testScore2;
}

// ----------------------------------------------------
// Getter for finalExamScore
public double getFinalExamScore() {
    return finalExamScore;
}

// Setter for finalExamScore
public void setFinalExamScore(double finalExamScore) {
    this.finalExamScore = finalExamScore;
}   

// ----------------------------------------------------
// Getter for average
public double getAverage() {
    return average;
}   

// I think this is essentially a setter for average
public double calculateEntireAverage() {
    average = (testScore1*0.25 + testScore2*0.25 + finalExamScore*0.5);
    // am I just supposed to use a getter / setter for the average instead of making a method like this?
    return average;
}   
}
\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

Here are some comments regarding how I would approach this:

Coding Style

  • Avoid using comments to document things that are evident: For example, "Getter for average" is not needed when the method is a very standard getAverage method, which most people will know what is and what to expect from it. You will find many different positions on this topic, but I try to add comments just for situations where the purpose of the code is not evident, or something is used/done in a not very standard way.
  • Code separators: I wouldn't recommend using separators like the one you ask about for separating portions of code. IT is not very standard, and the code separation should come from good class and method definitions, and not from artificial elements.

Main Programing Considerations

  • Requirements and Objective: always start with clear objectives and requirements. In your case, I would say (from your comments) that it is to calculate the average score for your students. This is important because it allows you to focus on what's required, and avoid what's not needed.
  • Constructor: as you ask in your comments, probably the best way to create a Student is not doing it with a "blank" object, which is what you do when you don't use a constructor to set its initial state. Passing the student name to the constructor would be a better way to initialize this type of object, because there's no point (in this particular case) to create an instance of Student that has no name and belongs to nobody.
  • Extensibility: the way things are now, adding a new test would require more code than I would like. Adding 10 tests would require a lot of code. I would approach this using a collection of Tests, and would decide which methods I really need to supply the required functionality.
  • Decomposition: as your comments suggest, each Test can have it's own score and weight. I would create a Test class to keep those attributes (I would also consider adding a Name property to identify each test easily (in case I decide to print or produce the full Test summary for the Student).
  • Getters and setters: it is ok to have getter and setters for your class properties, but just because you have properties doesn't mean you need to provide setters and/or getters for them. I would choose for which properties I really need to have getters and setters, according to your objectives and requirements. Some properties can be modified and consumed internally (only from within the class), and that's fine. By choosing wisely the public methods each class provides (the class API), you simplify the class API, which IMHO is always desirable.

With this comments in mind, this is the code I produced to solve your problem:

Application.java

public class TestCases {  
    public static void main(String[] args) {
        Student student1 = new Student("Bob");
        student1.addTestScore(new Test("test1", 80, 0.25));
        student1.addTestScore(new Test("test2", 60, 0.25));
        student1.addTestScore(new Test("final", 90, 0.5));

        student1.printStudentTestSummary();
        student1.printStudentTestAverage();
    }
}  

Student.java

public class Student{

    private String name;
    private ArrayList<Test> tests = new ArrayList<>();

    public Student(String name) {
        this.name = name;
    }

    public void addTestScore(Test test) {
        tests.add(test);
    }   

    public void printStudentTestAverage() {
        float average = 0;
        for (Test test: tests) {
            average += test.getWeightedScore();
        }
        System.out.println("Test average for student: " + average);
    }

    public void printStudentTestSummary() {
        System.out.println("Test scores for student: " + name);
        for (Test test: tests) {
            System.out.println(test.toString());
        }
    }
}

Test.java

public class Test {

    private String name;
    private int score;
    private double weight;

    public Test(String name, int score, double weight) {
        this.name = name;
        this.score = score < 0 ? 0 : score; // basic check for valid score
        this.weight = weight < 0 ? 0 : weight; // basic check for valid weight
    }

    public double getWeightedScore() {
        return score * weight;
    }

    public String toString() {
        return "Test: " + name + ". Score: " + score + " (w " + weight * 100 + "%).";
    }
}

Finally, see that you can now add more complex validations to scores and weights, if needed. You can easily extend this code now to support additional use cases also.

Hope this helps!

\$\endgroup\$
6
  • \$\begingroup\$ Could you explain what this line means? I don't understand the syntax. this.score = score < 0 ? 0 : score; I assume it means it has to be within a certain range to be a valid score, but you could explain in simple terms and break it down for me? \$\endgroup\$ Commented Aug 12, 2016 at 18:33
  • \$\begingroup\$ @JonathanWang that is Java's ternary operator. Basically, a short/inlined if then else. \$\endgroup\$ Commented Aug 12, 2016 at 18:38
  • \$\begingroup\$ I haven't learned that yet, is there another way to make sure that score is between 0 and 100? \$\endgroup\$ Commented Aug 12, 2016 at 18:42
  • \$\begingroup\$ @JonathanWang you can substitute with if (score < 0) { this.score = p } else { this.score = score } \$\endgroup\$ Commented Aug 12, 2016 at 18:43
  • \$\begingroup\$ not sure what you mean by that comment, could you reiterate? \$\endgroup\$ Commented Aug 12, 2016 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.