Я был бы очень признателен за отзывы о моем калькуляторе OOP Household Outgoings. Моя цель — развиваться в ООП. Использовал ли я хорошие методы ООП? Как я могу это улучшить? И все, что вы можете добавить. Заранее большое спасибо всем, кто тратит свое время на его обзор. Я так многому научился на этом сайте, и он сделал меня лучшим программистом. Обратите внимание, я использовал венгерскую нотацию и знаю ее плохо, но у меня есть причины для ее использования. Кроме того, я знаю, что не все было проверено с точки зрения входных данных, но мне просто нужен обзор того, насколько хорошо я использовал ООП. Большое спасибо!
Это пример вывода моей программы. Примечание: поддельный адрес.
// Homeowner Breakdown System.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <vector>
#include <istream>
#include <string>
class Person {
private:
std::string m_sName;
double m_dMonthlyIncome;
public:
Person() :m_sName{ "" }, m_dMonthlyIncome{ 0 }{}
Person(std::string sName, double dMonthlyIncome) :
m_sName{ sName }, m_dMonthlyIncome{ dMonthlyIncome }
{}
void set_name(std::string sName) {
m_sName = sName;
}
void set_monthly_income(double dMonthlyIncome) {
m_dMonthlyIncome = dMonthlyIncome;
}
std::string get_name() const { return m_sName; }
double get_monthly_salary() const { return m_dMonthlyIncome; }
};
class Outgoing {
private:
std::string m_sName;
double m_dCostPerMonth;
public:
Outgoing() :m_sName{ "" }, m_dCostPerMonth{ 0 }{}
Outgoing(std::string sName, double dCostPerMonth) :m_sName{ sName }, m_dCostPerMonth{dCostPerMonth} {}
std::string get_outgoing_name() const { return m_sName; }
double get_cost_per_month() const { return m_dCostPerMonth; }
};
class Household {
private:
std::vector<Person>m_objPeople;
std::string m_sAddress;
int m_iNumberOfAdultsInHousehold;
std::vector<Outgoing>objPleasureCosts;
std::vector<Outgoing>objBills;
public:
Household(std::string address)
:m_sAddress{ address }, m_iNumberOfAdultsInHousehold{0}
{}
void set_address(std::string address) { m_sAddress = address; }
std::string get_address()const { return m_sAddress; }
int get_number_of_adults_in_household()const { return m_iNumberOfAdultsInHousehold; }
double calculate_monthly_total_expenditure() const {
return calculate_monthly_bill_costs() + calculate_monthly_pleasure_costs();
}
void add_new_monthly_bill(Outgoing &&objOutgoingBill) {
objBills.emplace_back(objOutgoingBill);
}
void add_new_monthly_pleasure_cost(Outgoing &&objOutgoingPleasure) {
objPleasureCosts.emplace_back(objOutgoingPleasure);
}
double calculate_yearly_expenditure() const {
return (calculate_monthly_pleasure_costs() + calculate_monthly_bill_costs() * 12);
}
double calculate_monthly_savings() const {
return calculate_total_income() - (calculate_monthly_bill_costs() + calculate_monthly_pleasure_costs());
}
double calculate_total_income() const {
double dTotalIncome = 0;
for (const Person& objPerson : m_objPeople) {
dTotalIncome += objPerson.get_monthly_salary();
}
return dTotalIncome;
}
double calculate_total_monthly_outgoing_costs() const {
return (calculate_monthly_pleasure_costs() + calculate_monthly_bill_costs()) * 12;
}
double calculate_yearly_bill_costs() const {
return calculate_monthly_bill_costs() * 12;
}
double calculate_yearly_pleasure_costs() const {
return calculate_monthly_pleasure_costs() * 12;
}
double calculate_monthly_bill_costs() const {
double dSum = 0;
for (const Outgoing& objOutcoming : objBills) {
dSum += objOutcoming.get_cost_per_month();
}
return dSum;
}
double calculate_monthly_pleasure_costs() const {
double dSum = 0;
for (const Outgoing& objOutcoming : objPleasureCosts) {
dSum = objOutcoming.get_cost_per_month();
}
return dSum;
}
void add_person_to_household(Person objPerson) {
m_objPeople.emplace_back(objPerson);
m_iNumberOfAdultsInHousehold++;
}
void display_household_adults() const {
std::cout << "Household...n";
std::cout << "Address: " << m_sAddress << "n";
std::cout << "Occupants...n";
for (const Person& objPerson : m_objPeople) {
std::cout << objPerson.get_name() << "n";
}
}
void display_household_bills() const {
std::cout << "Bills...n";
for (const Outgoing& objBill : objBills) {
std::cout << "Name: " << objBill.get_outgoing_name() << "n";
std::cout << "Cost a month: " << char(156) << objBill.get_cost_per_month() << "n";
std::cout << objBill.get_cost_per_month() << "n";
}
}
};
class HomeownerBreakdownSystem {
private:
std::vector<Household> m_objHouseholds;
public:
auto find_household(std::string address) {
return std::find_if(m_objHouseholds.begin(), m_objHouseholds.end(), [&](auto& household) {return household.get_address() == address; });
}
void add_household_to_system(std::string address) {
m_objHouseholds.emplace_back(address);
}
auto& newly_added_household() {
return m_objHouseholds.back();
}
};
bool confirm_continue() {
unsigned char cOption = 0;
do {
std::cin >> cOption;
cOption = tolower(cOption);
if (cOption == 'y') {
return true;
}
else if (cOption == 'n') {
return false;
}
else
{
std::cout << "Your answer wasn't decisive, enter either y or n: ";
continue;
}
} while (true);
}
void display_outgoings_report(const Household &objHousehold) {
objHousehold.display_household_adults();
std::cout << "Household's Outgoing Total Cost: " << char(156) << objHousehold.calculate_monthly_total_expenditure() << "n";
std::cout << " . Bills total cost: " << char(156) << objHousehold.calculate_monthly_bill_costs() << "n";
std::cout << " . Pleasure total cost: " << char(156) << objHousehold.calculate_monthly_pleasure_costs() << "n";
objHousehold.display_household_bills();
std::cout << "Monthly savings: " << char(156) << objHousehold.calculate_monthly_savings() << "n";
std::cout << "Total yearly expenditure: " << char(156) << objHousehold.calculate_yearly_expenditure() << "n";
std::cout << " . Yearly Bill expenditure: " << char(156) << objHousehold.calculate_yearly_bill_costs() << "n";
std::cout << " . Yearly Pleasure expenditure: " << char(156) << objHousehold.calculate_yearly_pleasure_costs() << "n";
}
void establish_new_household(HomeownerBreakdownSystem &objSystem) {
std::string sHousehold;
std::cout << "Enter the address of household: ";
std::getline(std::cin >> std::ws, sHousehold);
objSystem.add_household_to_system(sHousehold);
}
void enter_occupants_for_new_household(Household& objHousehold) {
std::string sName;
double dMonthlySalary = 0;
unsigned char cOption = 0;
do
{
std::cout << "nEnter occupant's name: ";
std::getline(std::cin >> std::ws, sName);
std::cout << "Enter occupant's monthly income " << char(156);
std::cin >> dMonthlySalary;
objHousehold.add_person_to_household(Person{ sName, dMonthlySalary });
std::cout << "Do you wish to add another to " << objHousehold.get_address() << "? (y/n): ";
if (confirm_continue()) {
continue;
}
else
{
return;
}
} while (true);
}
void enter_monthly_bills_to_pay_for_new_household(Household& objHousehold) {
std::string sBillName;
double dCostPerMonth = 0;
unsigned char cOption = 0;
do
{
std::cout << "nEnter bill's name: ";
std::getline(std::cin >> std::ws, sBillName);
std::cout << "Enter bill's monthly cost: " << char(156);
std::cin >> dCostPerMonth;
objHousehold.add_new_monthly_bill(Outgoing{ sBillName, dCostPerMonth });
std::cout << "Do you wish to add another to bill? (y/n): ";
if (confirm_continue()) {
continue;
}
else
{
return;
}
} while (true);
}
void enter_monthly_pleasure_costs_for_new_household(Household& objHousehold) {
std::string sPleasureName;
double dCostPerMonth = 0;
unsigned char cOption = 0;
do
{
std::cout << "nEnter pleasure's name: ";
std::cin >> sPleasureName;
std::cout << "Enter pleasure's monthly cost: " << char(156);
std::cin >> dCostPerMonth;
objHousehold.add_new_monthly_pleasure_cost(Outgoing{sPleasureName, dCostPerMonth});
std::cout << "Do you wish to add another pleasure cost? (y/n): ";
if (confirm_continue()) {
continue;
}
else
{
return;
}
} while (true);
}
int main()
{
HomeownerBreakdownSystem objSystem;
establish_new_household(objSystem);
enter_occupants_for_new_household(objSystem.newly_added_household());
enter_monthly_bills_to_pay_for_new_household(objSystem.newly_added_household());
enter_monthly_pleasure_costs_for_new_household(objSystem.newly_added_household());
display_outgoings_report(objSystem.newly_added_household());
}
1 ответ
Вот некоторые вещи, которые могут помочь вам улучшить вашу программу.
Используйте необходимые #include
s
Код использует std::find_if
что означает, что он должен #include <algorithm>
. Сделать вывод было несложно, но если код закончен, это помогает рецензентам.
Удалите неиспользуемые переменные
В пределах enter_occupants_for_new_household
, enter_monthly_bills_to_pay_for_new_household
, и enter_monthly_pleasure_costs_for_new_household
переменная cOption
объявлен и установлен, но в остальном не используется. Его следует исключить из программы во всех трех местах.
Избегайте слишком длинных имен
При написании этого обзора я набрал calculate_monthly_pleasure_costs
много раз. Это утомительно! Проявляйте милосердие к другим программистам и используйте более короткие имена.
Не пишите геттеры и сеттеры для каждого класса
C ++ — это не Java, и писать функции получения и установки для каждого класса C ++ — не лучший стиль. Вместо этого переместите функции сеттера в конструкторы и очень внимательно подумайте, нужен ли вообще геттер. В этом коде Person
класс имеет публичные сеттеры и геттеры как для имени, так и для ежемесячного дохода. Если действительно желательно, чтобы что-либо могло независимо устанавливать любой член данных, тогда это должен быть struct
вместо. Увидеть C.2 для подробностей.
При необходимости используйте широкие струны
Код в настоящее время включает эту странную строку:
std::cout << "Enter occupant's monthly income " << char(156);
Это своеобразно из-за char(156)
в конце. Вы пытались напечатать «£», но это не способ сделать это. Вместо этого напишите такую строку:
std::cout << "Enter occupant's monthly income £";
Обратите внимание, что в зависимости от текущего locale
однако это может или не может отображаться должным образом. Увидеть этот вопрос как установить его явно.
Не включайте информацию о типе в имена переменных
Когда вы пишете что-то вроде m_dMonthlyIncome
в явном стремлении передать это double
, вы действительно активно вредите своему коду. Это делает его менее читаемым, более подверженным проблемам обслуживания, и это вообще плохая идея для строго типизированного языка, такого как C ++. Увидеть NL.5.
Исправить ошибку
Ошибка в calculate_monthly_pleasure_costs
в том, что он рассматривает только первые расходы, а не все они. Это легко исправить, используя следующее предложение.
Используйте стандартные алгоритмы
Вместо написания цикла я бы предпочел использовать std::accumulate
рассчитать сумму. Мы могли бы использовать лямбда для добавления вещей, но я думаю, что было бы разумно создать operator+
для Outgoing
класс вместо этого. Вот один из способов сделать это.
double operator+(double a, const Outgoing& bill) {
return a + bill.get_cost_per_month();
}
Теперь мы можем переписать calculate_monthly_pleasure_costs
:
double calculate_monthly_pleasure_costs() const {
return std::accumulate(objPleasureCosts.begin(), objPleasureCosts.end(), 0);
}
Однако я немного скептически отношусь к тому, что нам действительно нужно так много специальных функций, что приводит к следующему предложению.
Сверните интерфейс класса
Хороший, удобный интерфейс минимален, но достаточен. Это предполагает, что многие функции, такие как calculate_total_monthly_outgoing_costs
, calculate_yearly_bill_costs
, calculate_monthly_bill_costs
можно легко уронить. Предположим, ваши пользователи могут умножить на 12 или сложить два числа.
Раздельный ввод, вывод и расчет
С практической точки зрения обычно рекомендуется разделять ввод, вывод и вычисления для таких программ. Помещая их в отдельные функции, он изолирует конкретный ввод-вывод для вашей платформы (который, вероятно, будет уникальным для этой платформы или операционной системы) от логики вашей программы (которая не зависит от базовой ОС). В частности, enter_monthly_bills_to_pay_for_new_household
ссылается на Household
объект и возвращается void
. Я бы предложил лучший способ сделать это — не принимать никаких параметров и возвращать Outgoing
экземпляр класса.
Большое спасибо за ваш обзор! Чрезвычайно поучительно и многому научился. У меня было ощущение, что мои длинные имена переменных будут указаны. Обязательно сделаю их короче. Спасибо за перегрузку предложения оператора +! Это великолепно, и мы будем его применять. Должно быть, я пропустил самую верхнюю строку, когда скопировал и вставил этот код, поскольку в моей программе заголовок алгоритма включен. Спасибо еще раз!
— Джордж Остин Брэдли