Activity 2 Refactoring Code handout

// Initial version
public class Main {
  private static String processGrades(Scanner scanner) {
    double t = 0;
    int c = 0;
    while (scanner.hasNextLine()) {
      scanner.next("\\s*\\w+\\s*");
      scanner.next("\\s*\\w+\\s*");
      String l = scanner.next("[ABCDFW][+-]?");
      if (scanner.hasNextLine()) {
        scanner.nextLine();
      }
      switch (l) {
      case "A":
        t += 4.00;
        break;
      case "A-":
        t += 3.67;
        break;
      case "B+":
        t += 3.33;
        break;
      case "B":
        t += 3.00;
        break;
      case "B-":
        t += 2.67;
        break;
      case "C+":
        t += 2.33;
        break;
      case "C":
        t += 2.00;
        break;
      case "C-":
        t += 1.67;
        break;
      case "D+":
        t += 1.33;
        break;
      case "D":
        t += 1.00;
        break;
      case "F":
        t += 0.00;
        break;
      case "W":
        break;
      default:
        throw new RuntimeException();
      }
      if (!l.equals("W")) {
        c += 1;
      }
    }
    double gpa = c == 0 ? 0 : t / c;

    return String.format("Courses: %d\nGPA: %.2f\n", c, gpa);
  }
}
//  First refactoring
public class Main {
  private static String processGrades(Scanner scanner) {
    double total = 0;
    int courses = 0;
    while (scanner.hasNextLine()) {
      readPrefix(scanner);
      readCourseNo(scanner);
      String letter = readLetterGrade(scanner);
      readToEndOfLine(scanner);
      total += getGradeForLetter(letter);
      if (countsForCredit(letter)) {
        courses += 1;
      }
    }
    double gpa = computeGPA(courses, total);
    return formatSummary(courses, gpa);
  }

  private static void readPrefix(Scanner scanner) {
    scanner.next("\\s*\\w+\\s*");
  }

  private static void readCourseNo(Scanner scanner) {
    scanner.next("\\s*\\w+\\s*");
  }

  private static String readLetterGrade(Scanner scanner) {
    return scanner.next("[ABCDFW][+-]?");
  }

  private static void readToEndOfLine(Scanner scanner) {
    if (scanner.hasNextLine()) { scanner.nextLine(); }
  }

  private static double getGradeForLetter(String letterGrade) {
    switch (letterGrade) {
    case "A": return 4.00;
    case "A-": return 3.67;
    case "B+": return 3.33;
    case "B": return 3.00;
    case "B-": return 2.67;
    case "C+": return 2.33;
    case "C": return 2.00;
    case "C-": return 1.67;
    case "D+": return 1.33;
    case "D": return 1.00;
    case "F": return 0.00;
    case "W": return 0.00;
    default: throw new RuntimeException();
    }
  }

  private static boolean countsForCredit(String letter) {
    return !letter.equals("W");
  }

  private static double computeGPA(int courses, double total) {
    return courses == 0 ? 0 : total / courses;
  }

  private static String formatSummary(int courses, double gpa) {
    return String.format("Courses: %d\nGPA: %.2f\n", courses, gpa);
  }
}
//  Extracting the Summary class
public class Main {
  private static String processGrades(Scanner scanner) {
    Summary summary = new Summary();
    while (scanner.hasNextLine()) {
      readPrefix(scanner);
      readCourseNo(scanner);
      String letter = readLetterGrade(scanner);
      readToEndOfLine(scanner);
      summary.addGrade(letter);
    }
    return summary.format();
  }

  private static void readPrefix(Scanner scanner) {
    scanner.next("\\s*\\w+\\s*");
  }
  private static void readCourseNo(Scanner scanner) {
    scanner.next("\\s*\\w+\\s*");
  }
  private static String readLetterGrade(Scanner scanner) {
    return scanner.next("[ABCDFW][+-]?");
  }
  private static void readToEndOfLine(Scanner scanner) {
    if (scanner.hasNextLine()) { scanner.nextLine(); }
  }

  static double getGradeForLetter(String letterGrade) {
    switch (letterGrade) {
    case "A": return 4.00;
    case "A-": return 3.67;
    case "B+": return 3.33;
    case "B": return 3.00;
    case "B-": return 2.67;
    case "C+": return 2.33;
    case "C": return 2.00;
    case "C-": return 1.67;
    case "D+": return 1.33;
    case "D": return 1.00;
    case "F": return 0.00;
    case "W": return 0.00;
    default: throw new RuntimeException();
    }
  }

  static boolean countsForCredit(String letter) {
    return !letter.equals("W");
  }
}

class Summary {
  private int courses = 0;
  private double total = 0.00;

  void addGrade(String letter) {
    this.total += Main.getGradeForLetter(letter);
    if (Main.countsForCredit(letter)) { this.courses += 1; }
  }

  String format() {
    return String.format("Courses: %d\nGPA: %.2f\n", courses, computeGPA());
  }

  private double computeGPA() {
    return courses == 0 ? 0 : total / courses;
  }
}
// Final version
public class Main {
  private static String processGrades(Scanner scanner) {
    Summary summary = new Summary();
    Processor processor = new Processor(scanner);
    while (processor.hasNext()) {
      summary.addGrade(processor.getNext());
    }
    return summary.format();
  }
}

class Processor {
  private final Scanner scanner;

  Processor(Scanner scanner) { this.scanner = scanner; }

  boolean hasNext() { return scanner.hasNextLine(); }

  Grade getNext() {
    readPrefix();
    readCourseNo();
    String letter = readLetter();
    readToEndOfLine();
    return new Grade(letter);
  }

  private void readPrefix() { scanner.next("\\s*\\w+\\s*"); }

  private void readCourseNo() { scanner.next("\\s*\\w+\\s*"); }

  private String readLetter() { return scanner.next("[ABCDFW][+-]?"); }

  private void readToEndOfLine() {
    if (scanner.hasNextLine()) { scanner.nextLine(); }
  }
}

class Summary {
  private int courses = 0;
  private double total = 0.00;

  void addGrade(Grade grade) {
    this.total += grade.getPoints();
    if (grade.countsForCredit()) { this.courses += 1; }
  }

  String format() {
    return String.format("Courses: %d\nGPA: %.2f\n", courses, computeGPA());
  }

  private double computeGPA() { return courses == 0 ? 0 : total / courses; }
}

class Grade {
  private final String letter;

  Grade(String letter) { this.letter = letter; }

  double getPoints() {
    switch (letter) {
    case "A": return 4.00; case "A-": return 3.67;
    case "B+": return 3.33; case "B": return 3.00; case "B-": return 2.67;
    case "C+": return 2.33; case "C": return 2.00; case "C-": return 1.67;
    case "D+": return 1.33; case "D": return 1.00;
    case "F": return 0.00; case "W": return 0.00;
    default: throw new RuntimeException();
    }
  }

  boolean countsForCredit() { return !letter.equals("W"); }
}