Почему этот код java не дает ожидаемого результата? - PullRequest
0 голосов
/ 08 апреля 2020

Программа должна выдавать правильную цену билета на основе age и gender клиента.

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Person p1 = new Person();

        System.out.println("Enter the passenger name:");
        String name = sc.next();
        p1.setName(name);

        System.out.println("Enter the gender:");
        char gen = sc.next().charAt(0);
        p1.setGender(gen);

        System.out.println("Enter the age:");
        int age = sc.nextInt();
        p1.setAge(age);

        BusTicket b1 = getTicketDetails();
        b1.setPerson(p1);

        b1.calculateTotal();

        System.out.println("Ticket no:"+b1.getTicketno());
        System.out.println("Passenger Name:"+p1.getName());
        System.out.println("Price of a ticket:"+b1.getTicketprice());
        System.out.println("Total Amount:"+b1.getTotalamt());
    }

    public static BusTicket getTicketDetails() {
        Scanner sc=new Scanner(System.in);

        System.out.println("Enter the ticket no:");
        int no=sc.nextInt();

        BusTicket t1=new BusTicket();
        t1.setTicketno(no);

        System.out.println("Enter the ticket price:");`enter code here`
        float cost=sc.nextFloat();
        t1.setTicketprice(cost);

        return t1;
    }
}
public class Person {
    private String name;
    private char gender;
    private int age;

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

    public String getName() {
        return this.name;
    }

    public void setGender(char gender){
        this.gender = gender;
    }

    public char getGender() {
        return this.gender;
    }

    public void setAge(int age){
        this.age = age;
    }

    public int getAge() {
        return this.age;
    }
}
public class BusTicket {
private int ticketNo;
    private float ticketPrice;
    private float totalAmount;
    private Person person;

    public void setTicketno(int no) {
        ticketNo = no;
    }

    public int getTicketno() {
        return this.ticketNo;
    }

    public void setTicketprice(float price){
        ticketPrice = price;
    }

    public float getTicketprice(){
        return this.ticketPrice;
      }

    public void setTotalamt(float amt) {
        totalAmount=amt;
    }

    public float getTotalamt() {
        return this.totalAmount;
    }

    public void setPerson(Person p) {
        p=new Person();
        person=p;
    }

    public Person getPerson() {
        return this.person;
    }

    public void calculateTotal() {
        if(16 > person.getAge())
            this.totalAmount = ticketPrice - (float) (ticketPrice * 0.50);
        else if(person.getAge() < 60)
            this.totalAmount = ticketPrice - (float) (ticketPrice * 0.25);
        else if (person.getGender() == 'f' || person.getGender() == 'F')
            this.totalAmount = ticketPrice - (float) (ticketPrice * 0.10);
        else
            this.totalAmount = ticketPrice;
    }
}

Метод calculateTotal не дает правильный вывод. Для каждой цены билета, результат дает половину от суммы. Условие if-else в функции calculateAmount не выполняется должным образом.

Что мне нужно изменить, чтобы получить ожидаемые результаты?

Тестовые случаи

Где Имя не имеет значения, а базовая цена билета составляет $100.00.

+-----|--------|-------------------|-----------------------------+
| Age | Gender | Expected Discount | Expected total ticket price |
|-----|--------|-------------------|-----------------------------|
| 15  |   M    |       0.50        |             $50.00          |
| 15  |   F    |       0.50        |             $50.00          |
|  4  |   M    |       0.50        |             $50.00          |
| 12  |   F    |       0.50        |             $50.00          |
|-----|--------|-------------------|-----------------------------|
| 61  |   M    |       0.25        |             $75.00          |
| 61  |   F    |       0.25        |             $75.00          |
| 99  |   M    |       0.25        |             $75.00          |
| 75  |   F    |       0.25        |             $75.00          |
|-----|--------|-------------------|-----------------------------|
| 16  |   F    |       0.10        |             $90.00          |
| 27  |   F    |       0.10        |             $90.00          |
| 48  |   F    |       0.10        |             $90.00          |
| 60  |   F    |       0.10        |             $90.00          |
|-----|--------|-------------------|-----------------------------|
| 16  |   M    |       0.00        |             $100.00         |
| 27  |   M    |       0.00        |             $100.00         |
| 48  |   M    |       0.00        |             $100.00         |
| 60  |   M    |       0.00        |             $100.00         |
+-----|--------|-------------------|-----------------------------+

Ответы [ 2 ]

3 голосов
/ 08 апреля 2020

Проблема в том, что вы перезаписываете человека, когда делаете:

public void setPerson(Person p){
      p =new Person();
      person=p;
}

Замените этот установщик на:

public void setPerson(Person p){
    this.person=p;
}
2 голосов
/ 08 апреля 2020

Здесь что-то вроде неизменности будет вашим другом.

@ Ner правильно , указав , что метод setPerson() это то, что нарушает ваш код, поскольку вы создаете новый объект Person вместо того, чтобы использовать тот, который передается методу setter, setPerson, в классе BusTicket.

Это приводит к потере данные в переданном Person объекте, который необходим для расчета.

По умолчанию name персонажа null, символ gender по умолчанию 'u0000' и age по умолчанию будет 0. Это значение age - это то, что ловит первый оператор if в методе вычисления класса BusTicket каждый раз, поскольку 0 меньше 16.

One Чтобы внести изменения, можно взять:

public void setPerson(Person p) {
    p=new Person();
    person=p;
}

и преобразовать его в:

public void setPerson(final Person person) {
    this.person = person;
}

Обратите внимание на использование ключевого слова final здесь. Это отличный способ защитить входящие аргументы метода от изменения их ссылки в области действия метода.

Альтернативная структура кода

Я бы предложил следующие альтернативы вашим классам, поскольку они иллюстрируют лучшие практики, которые предотвратили бы появление подобной ошибки.

import java.util.Scanner;
import java.util.function.Function;

public class Main {
    public static void main(final String[] args) {
        try(final Scanner scanner = new Scanner(System.in)) {
            final Person person = getPersonUsing(scanner);
            final BusTicket busTicket = getBusTicketForPersonUsing(scanner).apply(person);
            System.out.printf("%n%s", busTicket);
        }
    }

    private static Person getPersonUsing(final Scanner scanner) {
        System.out.print("Enter the passenger name: ");
        final String name = scanner.nextLine();

        System.out.print("Enter the gender: ");
        final Person.Gender gender = Person.Gender.valueOf(scanner.next().charAt(0));

        System.out.print("Enter the age: ");
        final int age = scanner.nextInt();

        return new Person(name, gender, age);
    }

    private static Function<Person, BusTicket> getBusTicketForPersonUsing(final Scanner scanner) {
        return person -> {
            System.out.print("Enter the ticket number: ");
            final int ticketNumber = scanner.nextInt();

            System.out.print("Enter the base ticket price: ");
            final float baseTicketPrice = scanner.nextFloat();

            return new BusTicket(ticketNumber, baseTicketPrice, person);
        };
    }
}
public class Person {
    private final String name;
    private final Person.Gender gender;
    private final int age;

    public Person(
            final String name,
            final Person.Gender gender,
            final int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public Person.Gender getGender() {
        return this.gender;
    }

    public int getAge() {
        return this.age;
    }

    @Override
    public String toString() {
        return String.format(
                "%s (%02d %s)",
            getName(),
            getAge(),
            getGender().asSingleLetter());
    }

    public enum Gender {
        FEMALE,
        MALE;

        public String asSingleLetter() {
            return String.valueOf(name().charAt(0));
        }

        public static Gender valueOf(final char gender) {
            switch (Character.toUpperCase(gender)) {
            case 'F': return FEMALE;
            case 'M': return MALE;
            default:
                throw new IllegalArgumentException(String.format("Gender [%s] could not be determined.", gender));
            }
        }
    }
}
import java.util.function.Function;

public class BusTicket {
    private final int ticketNumber;
    private final float baseTicketPrice;
    private final float totalAmount;
    private final Person person;

    public BusTicket(
            final int ticketNumber,
            final float baseTicketPrice,
            final Person person) {
        this.ticketNumber = ticketNumber;
        this.baseTicketPrice = baseTicketPrice;
        this.totalAmount = calculateTotal(person).apply(baseTicketPrice);
        this.person = person;
    }

    public int getTicketNumber() {
        return this.ticketNumber;
    }

    public float getBaseTicketPrice() {
        return this.baseTicketPrice;
    }

    public float getTotalAmount() {
        return this.totalAmount;
    }

    public Person getPerson() {
        return person;
    }

    @Override
    public String toString() {
        return String.format(
                "%nTicket no: %d%n" + 
                "Passenger: %s%n" +
                "Base price of a ticket: $%.2f%n" +
                "Total Amount: $%.2f%n",
            getTicketNumber(),
            getPerson(),
            getBaseTicketPrice(),
            getTotalAmount());
    }

    private static float calculateDiscountForPerson(final Person person) {
        // 50% discount for age of 16
        if(person.getAge() < 16) {
            return 0.50f;
        // 25% discount for age over 60
        } else if(person.getAge() > 60) {
            return 0.25f;
        // 10% discount for females
        } else if (person.getGender() ==  Person.Gender.FEMALE) {
            return 0.10f;
        // 0% discount for men between 16 and 60
        } else {
            return 0.00f;
        }
    }

    private static Function<Float, Float> calculateTotal(final Person person) {
        return baseTicketPrice ->
            baseTicketPrice * (1.0f - calculateDiscountForPerson(person));
    }
}
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import static com.shaba.Person.Gender.FEMALE;
import static com.shaba.Person.Gender.MALE;

import static org.junit.jupiter.api.Assertions.assertEquals;

class BusTicketTest {
    private static final int   TICKET_NUMBER     = 42;
    private static final float BASE_TICKET_PRICE = 100.0f;

    @Test
    void shouldReturnExpectedTicketPrice() {
        // Map of Person and Expected Discounted Ticket Price
        final Map<Person, Float> cases = new HashMap<> ();

        cases.put(new Person("Tom", MALE,   15), 50.0f);
        cases.put(new Person("Jen", FEMALE, 15), 50.0f);
        cases.put(new Person("Tom", MALE,    4), 50.0f);
        cases.put(new Person("Jen", FEMALE, 12), 50.0f);

        cases.put(new Person("Tom", MALE,   61), 75.0f);
        cases.put(new Person("Jen", FEMALE, 61), 75.0f);
        cases.put(new Person("Tom", MALE,   99), 75.0f);
        cases.put(new Person("Jen", FEMALE, 75), 75.0f);

        cases.put(new Person("Jen", FEMALE, 16), 90.0f);
        cases.put(new Person("Jen", FEMALE, 27), 90.0f);
        cases.put(new Person("Jen", FEMALE, 48), 90.0f);
        cases.put(new Person("Jen", FEMALE, 60), 90.0f);

        cases.put(new Person("Tom", MALE,   16), 100.0f);
        cases.put(new Person("Tom", MALE,   27), 100.0f);
        cases.put(new Person("Tom", MALE,   48), 100.0f);
        cases.put(new Person("Tom", MALE,   60), 100.0f);

        cases.forEach(this::assertExpectedTotalTicketPrice);
    }

    private void assertExpectedTotalTicketPrice(
            final Person person,
            final float expectedTotal) {
        assertEquals(expectedTotal, makeTestBusTicket().apply(person).getTotalAmount());
    }

    private Function<Person, BusTicket> makeTestBusTicket() {
        return person -> new BusTicket(TICKET_NUMBER, BASE_TICKET_PRICE, person);
    }
 }

Тестовые случаи

Эти тестовые случаи теперь происходят, как и ожидалось.

+-----|--------|-------------------|-----------------------------+
| Age | Gender | Expected Discount | Expected total ticket price |
|-----|--------|-------------------|-----------------------------|
| 15  |   M    |       0.50        |             $50.00          |
| 15  |   F    |       0.50        |             $50.00          |
|  4  |   M    |       0.50        |             $50.00          |
| 12  |   F    |       0.50        |             $50.00          |
|-----|--------|-------------------|-----------------------------|
| 61  |   M    |       0.25        |             $75.00          |
| 61  |   F    |       0.25        |             $75.00          |
| 99  |   M    |       0.25        |             $75.00          |
| 75  |   F    |       0.25        |             $75.00          |
|-----|--------|-------------------|-----------------------------|
| 16  |   F    |       0.10        |             $90.00          |
| 27  |   F    |       0.10        |             $90.00          |
| 48  |   F    |       0.10        |             $90.00          |
| 60  |   F    |       0.10        |             $90.00          |
|-----|--------|-------------------|-----------------------------|
| 16  |   M    |       0.00        |             $100.00         |
| 27  |   M    |       0.00        |             $100.00         |
| 48  |   M    |       0.00        |             $100.00         |
| 60  |   M    |       0.00        |             $100.00         |
+-----|--------|-------------------|-----------------------------+

Пример вывода

Enter the passenger name: Tom
Enter the gender: M
Enter the age: 98
Enter the ticket number: 2346
Enter the base ticket price: 100

Ticket no: 2346
Passenger: Tom (98 M)
Base price of a ticket: $100.00
Total Amount: $75.00
...