Prosty program obiektowy - wskaźnik BMI

0

Czy w tym programie warto pomyśleć nad pobraniem danych w metodzie , czy lepiej zostawić jak jest. W każdym razie działa.

//Napisz program, który oblicza wskaźnik masy ciała BMI.Program ma prosić
//użytkownika o podanie wagi w kg oraz wzrostu w metrach.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CS_AE_3._6
{
    class Bmi
    {
        private int masa;
        private double wzrost;
        public double ObliczBmi()
        {
            return masa / (wzrost * wzrost);
        }

        public void Kategoria(double bmi)
        {
            //Funcja klasyfikuje stopień otyłości
            if (bmi < 16.0)
                Console.WriteLine("Jesteś wygłodzony!");
            else if (bmi >= 16.0 && bmi <=16.99)
                Console.WriteLine("Jesteś wychudzony!");
            else if (bmi >=17.0 && bmi <= 18.49)
                Console.WriteLine("Masz niedowagę!");
            else if (bmi >= 18.5 && bmi < +24.99)
                Console.WriteLine("Mieścisz się w normie!");
            else if (bmi >= 30.0 && bmi <= 34.99)
                Console.WriteLine("Masz I stopień otyłości");                
            else if (bmi >= 35.0 && bmi <=39.99)
                Console.WriteLine("Masz II stopień otyłości(otyłość kliniczna)");
            else if (bmi >= 40.0)
                Console.WriteLine("Masz III stopień otyłości(otyłość skrajna)");
        }

        public Bmi(int masa, double wzrost)
        {
            this.masa = masa;
            this.wzrost = wzrost;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Podaj ile ważysz w kg");
                int kg = Int32.Parse(Console.ReadLine());
                Console.WriteLine("Podaj twój wzrost w metrach");
                double mtr = Double.Parse(Console.ReadLine());

                Bmi o1 = new Bmi(kg, mtr);
                double wynik = o1.ObliczBmi();
                Console.WriteLine("BMI wynosi {0}", Math.Round(wynik, 2));

                o1.Kategoria(wynik);
            }
            catch
            {
                Console.WriteLine("Wprowadzono nieprawidłowe wartości!");
            }

            Console.ReadKey();

        }
    }
}

0

Porównania przy bmi zamiast tego brzydkiego <= możesz zamienić znaczkiem <.
< 18.5 jest lepsze niż <= 18.49
Bo złapie "całą nieskończoność" między 18.49 i 18.50, która to może wyniknąć z obliczeń i Twój obecny program się w takich sytuacjach wyłoży :)

Twoja metoda Kategoria nie powinna wypisywać danych, powinna zwracać string. Powinna też nazywać się inaczej.

Przydałaby się też metoda zmieniająca wagę i wzrost. Oblicz BMI powinno się nazywać getBMI().

0

Spine
Czy chodzi o coś takiego?

//Napisz program, który oblicza wskaźnik masy ciała BMI.Program ma prosić
//użytkownika o podanie wagi w kg oraz wzrostu w metrach.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CS_AE_3._6
{
    struct Bmi //W tym przypadku program zadziała tak samo z "class"
    {
        private  int masa;
        private  double wzrost;

        

        public double getBmi()
            //Metoda obicza wskaźnik BMI
        {
            Console.WriteLine("Podaj ile ważysz w kg");
            masa = Int32.Parse(Console.ReadLine());
            Console.WriteLine("Podaj twój wzrost w metrach");
            wzrost = Double.Parse(Console.ReadLine());

            return masa / (wzrost * wzrost);
        }

        public string ObesLevel(double bmi)
        { 

            //Metoda klasyfikuje stopień otyłości
            if (bmi < 16.0)
            {
                return "Jesteś wygłodzony!";
            }
            else if (bmi >= 16.0 && bmi < 17.0)
            {
                return "Jesteś wychudzony!";
            }
            else if (bmi >= 17.0 && bmi < 18.5)
            {
                return "Masz niedowagę!";
            }
            else if (bmi >= 18.5 && bmi < 25.0)
            {
                return "Mieścisz się w normie!";
            }
            else if (bmi >= 30.0 && bmi < 35.0)
            {
                return "Masz I stopień otyłości";
            }
            else if (bmi >= 35.0 && bmi < 40.0)
            {
                return "Masz II stopień otyłości(otyłość kliniczna)";
            }
            else //if (bmi >= 40.0)
            {
                return "Masz III stopień otyłości(otyłość skrajna)";
            }

           
        }
        

        public Bmi(int masa, double wzrost)
        {
            this.masa = masa;
            this.wzrost = wzrost;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Bmi o1 = new Bmi();
                double wynik = o1.getBmi();
                Console.WriteLine("BMI wynosi {0}", Math.Round(wynik, 2));
                Console.WriteLine(o1.ObesLevel(wynik));
            }
            catch
            {
                Console.WriteLine("Wprowadzono nieprawidłowe wartości!");
            }

            Console.ReadKey();

        }
    }
}

1

Nie.

  • niechże BMI będzie z powrotem klasą.... struktury to okrojone klasy, nie musisz sobie nimi zaprzątać głowy...
  • getBMI nie może służyć do pobierania i wyświetlania danych, getBMI ma służyć innemu programiście do pobrania wartości wyliczonego BMI, czyli tutaj tylko zwracamy wyliczone BMI, żadnych innych operacji!
  • ObesLevel ok, tylko ja bym to nazwał getObesityDescription() albo getObesityReport(), no i masz lukę w przedziale <25; 30);
  • masz tylko jeden konstruktor, nie przekazujesz mu argumentów w klasie Program, to nie powinno działać;
  • dobrze by było w klasie BMI zaimplementować metodę ToString(), która wypisze odpowiednio sformatowane dane - https://docs.microsoft.com/pl-pl/dotnet/csharp/programming-guide/classes-and-structs/how-to-override-the-tostring-method - ta metoda powinna użyć metod getBMI() oraz getObesityReport() i sformatować te dane według Twojego uznania ;)

O dane dla konstruktora BMI, powinieneś poprosić w klasie Program. Ewentualnie napisz statyczną metodę w klasie BMI, która:

  • pobierze dane od użytkownika;
  • utworzy obiekt BMI podając te dane do konstruktora;
  • zwróci obiekt BMI, albo od razu wynik metody ToString() obiektu BMI;

Wynik działania tej statycznej metody będziesz mógł wypisać w klasie Program.

0
Spine napisał(a):
  • getBMI nie może służyć do pobierania i wyświetlania danych, getBMI ma służyć innemu programiście do pobrania wartości wyliczonego BMI, czyli tutaj tylko zwracamy wyliczone BMI, żadnych innych operacji!

Nie wiem czy tak jest lepiej. getBMI w ogóle nie powinna się tak nazywać. Ja bym zrobił "bardziej funkcyjnie". Metoda CalcBMI, do niej parametry i ona zwraca BMI. To jest prostacka matematyka.

0

Sporo pozmieniałem w kodzie. Co prawda nie do końca jak sugerowano, ale wciąz się uczę.

//Napisz program, który oblicza wskaźnik masy ciała BMI.Program ma prosić
//użytkownika o podanie wagi w kg oraz wzrostu w metrach.

using System;

namespace CS_AE_3._6
{
    class Bmi
    {
        private int Weight;
        private double Height;


        public void GetData()
        {
             Console.WriteLine("Podaj ile ważysz w kg");
             Weight = Int32.Parse(Console.ReadLine());
             if (Weight <= 0) DataError();
             Console.WriteLine("Podaj twój wzrost w metrach");
             Height = Double.Parse(Console.ReadLine());
             if (Height <= 0) DataError();
        }

        public double CountBMI() => Weight / (Height * Height);


        public void PrintBMI(double result)
        {
            Console.WriteLine($"BMI wynosi {Math.Round(result, 2)}");
        }

        public void ObesityLevel(double bmi)
        {
            //Funcja klasyfikuje stopień otyłości
            if (bmi < 16.0)
                Console.WriteLine("Jesteś wygłodzony!");
            else if (bmi >= 16.0 && bmi < 17.0)
                Console.WriteLine("Jesteś wychudzony!");
            else if (bmi >= 17.0 && bmi < 19.0)
                Console.WriteLine("Masz niedowagę!");
            else if (bmi >= 18.5 && bmi < 30.0)
                Console.WriteLine("Mieścisz się w normie!");
            else if (bmi >= 30.0 && bmi < 35.0)
                Console.WriteLine("Masz I stopień otyłości");
            else if (bmi >= 35.0 && bmi < 40.0)
                Console.WriteLine("Masz II stopień otyłości(otyłość kliniczna)");
            else if (bmi >= 40.0)
                Console.WriteLine("Masz III stopień otyłości(otyłość skrajna)");
        }

        public void DataError()
        {
            throw new Exception("Wprowadzono nieprawidłowe dane!");
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Bmi o1 = new Bmi();
                o1.GetData();
                o1.PrintBMI(o1.CountBMI());
                o1.ObesityLevel(o1.CountBMI());

            }
            catch(Exception e)
            {
                Console.WriteLine(e);
            }

            Console.ReadKey();
        }
    }
}

2

Dalej błąd.... Co się stanie jak bmi będzie równe 16.995? Przez tyle czasu mogłeś chociaż wziąć do serca to co pisałem.....

2

Błąd podczas pobierania danych od użytkownika nie jest sytuacją wyjątkową i nie nie należy łapać od tego wyjątku. Wyjątki są drogie i nie należy ich nadużywać jeśli sytuacja tego nie wymaga. Jeśli chcesz się upewnić, że użytkownik na pewno wpisał poprawną liczbę to zrób coś w stylu:

int result = 0;
while (!int.TryParse(Console.ReadLine(), out result)) ;

W Twoim programie żaden try catch nie jest w ogóle potrzebny.

Na dobrą sprawę klasa BMI może wyglądać tak:

    class BMI // a nawet struct - poniżej napisane dlaczego
    {
        public double Weight { get; private set; }
        public double Height { get; private set; }

        public double Result
        {
            get => Weight / Height * Height;
        }

        public BMI(double weight, double height)
        {
            Weight = weight;
            Height = height;
        }
    }

Całę resztę operacji przenieś natomiast to osobnej klasy, która wykonuje zadania na gotowym obiekcie klasy powyższej.
Co więcej, w tym wypadku BMI powinna być nawet strukturą, a nie klasą, ponieważ dane przechowywane wewnątrz są jedynie typami wartościowymi i nie ma potrzeby opakowywania ich w typ referencyjny.

PS: Nazwy pól prywatnych piszemy w C# z małej litery.

1

Przede wszystkim chodziło mi o problem dzielenia przez zero w aplikacji. Reszta poszła z rozpędu.

No ale podczas pobierania danych można wyeliminować zero całkowicie. Wyjątek jest do tego niepotrzebny. Dla zera każdy wynik jest tutaj bez sensu. Starczy lekko zmodyfikować odczyt:

int result = 0;
while (!int.TryParse(Console.ReadLine(), out result) || result == 0) ; // dla double analogicznie jak w getterze

Albo gettera:

public double Result
{
    get => Weight / Math.Abs(Height) < 0.001 ? 1.0 : Height * Height;
}
0
  1. Klasa BMI nie powinna zajmować się pobieraniem danych od użytkownika - to powinno być robone w Main/osobnej metodzie w klasie Program
  2. Klasa powinna się nazywać BMICalculator lub coś w tym stylu - wzrost i wagę przyjmować w konstruktorze
    3.Klasa nie powinna zajmować się wypisywaniem poziomu otyłości. Moim zdaniem w tym wypadku moim zdaniem można wporowadzić enuma definiującego stopnie otyłości i jego zwracać. Zwrócony enum mapujesz na string w main/osobnej metodzie klasy Program. Co jeśli chciałbyś użyc klasy do oblicznia BMI w innym projekcie np. Windows Forms ?
  3. public double CountBMI() => Weight / (Height * Height); - czemu to jest metoda a nie właściwość ?
2

Brakuje obsługi płci.

0

BMI to jest pojedyncza wartość liczbowa niezawierająca w sobie informacji o wadze i wzroście. Jaki jest zatem sens robienia klasy BMI i plami Height i Weight? Jak dla mnie to się fizycznie nie komponuje.
Tak czy siak, nie powinno się mieszać pobierania i wyświetlania danych z obliczeniami. A coś takiego jak ObesityLevel to powinien być enum zwracany z metody klasy zajmującej się obliczeniami.

I co jest w końcu celem zadania? Obliczenie BMI czy wyświetlenie jego interpretacji?

0

Myślałem to zrobić w taki sposób, jak poniżej, ale gubię zakresy:

 public enum ObesityLvl { lvl1, lvl2, lvl3, lvl4, lvl5, lvl6, lvl7 }

        public void getObesityReport(ObesityLvl ol)
        {
            int i = (int)ol;
            switch(i)
            {
                case 0:                   
                        Console.WriteLine("Jesteś wygłodzony!");
                    break;
                case 1:
                        Console.WriteLine("Jesteś wychudzony!");
                    break;
                case 2:                    
                        Console.WriteLine("Masz niedowagę!");
                    break;
                case 3:                    
                        Console.WriteLine("Mieścisz się w normie!");
                    break;
                case 4:                    
                        Console.WriteLine("Masz I stopień otyłości");
                    break;
                case 5:
                    Console.WriteLine("Masz II stopień otyłości(otyłość kliniczna)");
                    break;
                case 6:
                        Console.WriteLine("Masz III stopień otyłości(otyłość skrajna)");
                    break;
               
            }
        }

2

Po to wymyślono enumy, żeby nie musieć operować na nic nieznaczących liczbach. To rzutowanie enuma na int jest bez sensu.

1

Dodatkowo nie używaj console writeline wewnątrz tej metody. Niech metoda zwraca stringa zamiast sama wypisywać. Aha mam nadzieję że ta metoda nie jest zdefiniowana w klasie BMI ? 😉 Nie powinna. Idealnie byłoby zrobić to jako metoda rozszerzenia dla klasy BMI ale to raczej ponad program tego zadania. I na miłość Boska , czemu konwencja nazw metody z Javy ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1