Kalkulator Kelas (Versi OOP Baru dari sebelumnya)

Dec 19 2020

Saya mencoba mengembangkan cara berpikir OOP. Saya berharap seseorang akan berbaik hati meluangkan waktu mereka yang berharga untuk meninjau program OOP Kalkulator Nilai saya. Seperti biasa, saya ingin tahu apa yang telah saya lakukan dengan baik, apa yang harus saya perbaiki, dan saran tentang bagaimana saya mungkin dapat meningkatkan apa yang saya miliki? Ngomong-ngomong, aku punya kelas yang disebut Kelas. Saya mungkin harus mengawalnya dengan "cls" agar tidak membingungkan. Perlakukan program ini sebagaimana mestinya, saya belum memeriksanya dengan kesalahan. Inti dari program ini adalah untuk mengembangkan dalam OOP.

   // Task 1.cpp : This file contains the 'main' function. Program execution begins and ends there.


#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
class TestPaper
{
public:
    int m_scoreOutOf;  
    bool checkBoundary(int value, int boundary) {
        if (value < 0 || value > boundary) {
            std::cout << "Score must be between " << " 0 and " << boundary << ". Please try again.\n";
            return false;
        }
        return true;
    }

};
class Student {
private:
    std::string m_name;
    int m_scoreGot;
public:
   
    Student(std::string name, int scoreGot)
        :m_name(name), m_scoreGot(scoreGot){}

    std::string getName() const { return m_name; }
    int getScoreGot() const { return m_scoreGot; }
};

class Class {
private:
    std::vector<Student>students;
public:
    void AddStudent(TestPaper& testPaper) {
        std::string name = "";
        int scoreGot = 0;
        std::cout << "Enter student name: ";
        std::getline(std::cin >> std::ws, name);
        do
        {
            std::cout << "\nWhat did " << name << " score?\nEnter a score between 0 and "
                << testPaper.m_scoreOutOf << ": ";
            std::cin >> scoreGot;
        } while (testPaper.checkBoundary(scoreGot, testPaper.m_scoreOutOf) == false);
        students.push_back({ name, scoreGot });
    }

    std::vector<Student>& accessStudents() { return students; }
};

class GradeCalculator {
    TestPaper m_testPaper;
    Class m_ClassOfStudents;
public:
    GradeCalculator(TestPaper testPaper, Class classOfStudents) :m_testPaper(testPaper), m_ClassOfStudents(classOfStudents) {}
    void DisplayMenu() {

        std::cout << "\n1. Add student and their grade\n";
        std::cout << "2. Calculate class score\n";
        std::cout << "3. Modify testpaper (haven't implemented this yet)\n";
    }
    

    double averageGrade() {
        auto sum = std::transform_reduce(m_ClassOfStudents.accessStudents().begin(), m_ClassOfStudents.accessStudents().end(), 0.0, std::plus<>(),
            [&](auto& student) { return calculateGradePercentage(student); });
        return sum / m_ClassOfStudents.accessStudents().size();
    }
    double calculateGradePercentage(Student &student)
    {
        return static_cast<double>(student.getScoreGot()) / static_cast<double>(m_testPaper.m_scoreOutOf) * 100;
    }
    void DisplayResult() {
        for (auto& student : m_ClassOfStudents.accessStudents()) {
            std::cout << "Percentage scores are: \n";
            std::cout << student.getName() << ": " << calculateGradePercentage(student) << "%\n";
        }
        std::cout << "Average grade perecentage: " << averageGrade() << "%\n";
    }
    void runProgram() {

        int menuChoice = 0;
        while (true)
        {
            DisplayMenu();
            std::cout << "\nEnter a choice from the menu: ";
            std::cin >> menuChoice;
            switch (menuChoice)
            {
            case 1:
                m_ClassOfStudents.AddStudent(m_testPaper);
                break;
            case 2:
                DisplayResult();
                break;
            default:
                std::cout << "Invalid choice!\n";
            }
        }
    }
};

int main()
{
    TestPaper testPaper({ 20 });
    Class classOfStudents;
    GradeCalculator calculator(testPaper, classOfStudents);
    calculator.runProgram();
   
}

Jawaban

6 Edward Dec 19 2020 at 09:35

Berikut beberapa hal untuk membantu Anda meningkatkan program Anda.

Jangan gabungkan I / O dengan operasi data

Secara umum, memiliki std::getlinedan di std::coutdalam kelas data seperti Classitu bukanlah ide yang baik. Kelas akan lebih sulit digunakan kembali. Praktek yang lebih baik adalah untuk menjaga data ( Student, Class, dll) terpisah dari mendapatkan masukan dari pengguna. The MVC pola desain sering berguna untuk program seperti ini. Pertimbangkan untuk menggunakan sesuatu seperti ConsoleMenukelas seperti dalam jawaban ini .

Gunakan semantik bergerak jika praktis

Dalam AddStudentfungsinya, kami memiliki baris ini:

students.push_back({ name, scoreGot });

Lebih baik menggunakan emplace_backyang memberi tahu kompiler bahwa ia tidak perlu membuat dan menyalin, tetapi aman untuk membuat objek pada tempatnya.

Pikirkan kembali antarmuka kelas

The Classkelas memiliki fungsi anggota ini:

std::vector<Student>& accessStudents() { return students; }

Ini ide yang buruk. Ini mengembalikan referensi ke anggota kelas internal. Pikirkan apa yang terjadi jika Classinstance dihapus tetapi beberapa entitas eksternal masih menyimpan referensi ke data yang sudah tidak ada lagi. Satu-satunya tempat yang digunakan adalah di dalam GradeCalculator::averageGrade()dan GradeCalculator::DislayResult()itu merupakan indikator kuat bahwa ada sesuatu yang tidak beres di antarmuka kelas. Saya sarankan membuat averageGrade()fungsi menjadi Classfungsi anggota.

Gunakan default jika memungkinkan

The Studentkonstruktor pada dasarnya sama dengan yang seharusnya dihasilkan oleh compiler. Untuk mengurangi kemungkinan kesalahan, itu bisa dihilangkan begitu saja.

Pikirkan tentang pengguna

Tidak ada cara yang jelas untuk keluar dari program dengan baik. Saya sarankan menambahkan item menu untuk itu. Juga, kemungkinan besar siapa pun yang benar-benar menggunakan program ini ingin memasuki seluruh kelas siswa dan kemudian menghitung skor untuk seluruh kelas. Harus berulang kali memilih "1. Tambah siswa ..." agak membosankan. Lebih baik program mengumpulkan masukan sampai nama kosong atau mungkin "keluar" dimasukkan, dan kemudian secara otomatis menampilkan skor. Lebih baik lagi mengizinkan input dari file teks.