Полиморфизм и уныние вопросы

Я читаю книгу о Java и в настоящее время на Polymorphism тема, а также как downcast ссылочная переменная. Тем не менее, я застрял в понимании концепции уныния. Ниже приведен пример для примера, которому я следую.

UML

Для всех объектов BasePlusCommissionEmployee они должны увеличить свою базовую зарплату на 10%. Другой Employee подклассы в соответствии с нормой. PayrollSystemTest содержит основной метод для запуска приложения.

// Fig. 10.9: PayrollSystemTest.java
// Employee hierarchy test program.

public class PayrollSystemTest
{
    public static void main(String[] args)
    {
        // create subclass objects
        SalariedEmployee salariedEmployee =
            new SalariedEmployee("John", "Smith", "111-11-1111", 800.00);
        HourlyEmployee hourlyEmployee =
            new HourlyEmployee("Karen", "Price", "222-22-2222", 16.75, 40.0);
        CommissionEmployee commissionEmployee =
            new CommissionEmployee(
            "Sue", "Jones", "333-33-3333", 10000, .06);
        BasePlusCommissionEmployee basePlusCommissionEmployee =
            new BasePlusCommissionEmployee(
            "Bob", "Lewis", "444-44-4444", 5000, .04, 300);

        System.out.println("Employee processed individually:");

        System.out.printf("%n%s%n%s: $%,.2f%n%n",
            salariedEmployee, "earned", salariedEmployee.earnings());
        System.out.printf("%s%n%s: $%,.2f%n%n",
            hourlyEmployee, "earned", hourlyEmployee.earnings());
        System.out.printf("%s%n%s: $%,.2f%n%n",
            commissionEmployee, "earned", commissionEmployee.earnings());
        System.out.printf("%s%n%s: $%,.2f%n%n",
            basePlusCommissionEmployee,
            "earned", basePlusCommissionEmployee.earnings());

        // create four-element Employee array
        Employee[] employees = new Employee[4];

        // initialize array with Employees
        employees[0] = salariedEmployee;
        employees[1] = hourlyEmployee;
        employees[2] = commissionEmployee;
        employees[3] = basePlusCommissionEmployee;

        System.out.printf("Employees processed polymorphically:%n%n");

        // generically process each element in array employees
        for (Employee currentEmployee : employees)
        {
            System.out.println(currentEmployee); // invokes toString

            // determine whether element is a BasePlusCommissionEmployee
            if (currentEmployee instanceof BasePlusCommissionEmployee)
            {
                // downcast Employee reference to
                // BasePlusCommissionEmployee reference
                BasePlusCommissionEmployee employee =
                    (BasePlusCommissionEmployee) currentEmployee;

                employee.setBaseSalary(1.10 * employee.getBaseSalary());

                System.out.printf(
                    "new base salary with 10%% increase is: $%,.2f%n",
                    employee.getBaseSalary());
            } // end if

            System.out.printf(
                "earned $%,.2f%n%n", currentEmployee.earnings());
        }  // end for

        // get type name of each object in employees array
        for (int j = 0; j < employees.length; j++)
            System.out.printf("Employee %d is a %s%n", j,
                employees[j].getClass().getName());
    } // end main
} // end class PayrollSystemTest

В книге также объясняется, что расширенный цикл for выполняет итерацию массива. employees и вызывает методы toString а также earnings с Employee переменная currentEmployee которому присваивается ссылка на другой Employee в массиве на каждой итерации. В результате выходные данные показывают, что конкретные методы для каждого класса вызываются и разрешаются во время выполнения в зависимости от типа объекта.

Для того, чтобы вызвать BasePlusCommissionEmployeeметоды getBaseSalary а также setBaseSalary на текущий Employee объект, оператор условия используется для проверки, является ли ссылка на объект BasePlusCommissionEmployee объект с помощью оператора instanceof и если условие истинно, объект должен быть понижен с Employee в BasePlusCommissionEmployee введите перед вызовом упомянутых методов.

Это серьезно смущает меня, потому что мы можем получить доступ к подклассам toString метод, но должен уменьшить объект, чтобы использовать другие методы, а именно getBaseSalary а также setBaseSalary? Почему это так?

3 ответа

Так как toString() определяется в Objectпоэтому доступны в каждом классе. Геттер и сеттер для базовой зарплаты доступны только в BasePlusCommissionEmployeeтак что вы не можете позвонить через Employee ссылка (что произойдет, если он ссылается на другой тип?).

Этот пример не тот, который вы видели бы в реальном коде. Использование instanceof для определения плохого стиля.

Когда вы хотите вызвать метод для экземпляра, методы, которые вы можете вызвать, зависят от нескольких вещей, среди объявленного типа экземпляра, модификатора метода и от того, откуда вы их вызываете.
В вашем примере это объявленный тип экземпляра, который должен вас заинтересовать.

Например, когда вы объявляете это:

String s = new String("string");

Вы можете вызывать доступные методы из String учебный класс.
Например:

s.toString();
s.trim();
etc...

В вашем случае, когда вы заявляете это:

BasePlusCommissionEmployee basePlusCommissionEmployee =
            new BasePlusCommissionEmployee(
            "Bob", "Lewis", "444-44-4444", 5000, .04, 300);
Employee currentEmployee = basePlusCommissionEmployee;

ты можешь сделать:basePlusCommissionEmployee.getBaseSalary() поскольку BasePlusCommissionEmployee объявленный тип предоставляет метод для.

Вы также можете сделать:basePlusCommissionEmployee.toString() а также currentEmployee.toString() потому что оба типа (Employee а также BasePlusCommissionEmployee) предоставить метод для toString() потому что метод является публичным методом из Object класс и все классы наследуются от Object класс, так что эти классы имеют toString() метод.

Но вы не можете сделать:currentEmployee.getBaseSalary() поскольку Employee объявленный тип не предоставляет метод для.

Чтобы обойти это, вы можете выполнить переход от базового класса к целевому дочернему классу:

Employee currentEmployee = basePlusCommissionEmployee;
((BasePlusCommissionEmployee)currentEmployee).getBaseSalary();

Стоит добавить в моих глазах: это на самом деле довольно плохой пример.

Удручение очень часто является признаком плохого дизайна; и это хорошо доказывает это правило.

Эта система начисления заработной платы не должна нуждаться в такой проверке "instanceof"; затем сделать некоторые конкретные вычисления для определенного подкласса.

В этом весь смысл использования полиморфизма: каждый из этих различных классов BasePlusCommissionEmployee и CommissionEmployee должен содержать средства для правильного расчета правильного оклада.

В данном случае следует придерживаться принципа TDA (не говорите). Хороший ОО говорит о том, что какой-то объект "делает вещь"; вместо того, чтобы просить объект о чем-либо, затем принять внешнее решение на основе этого внутреннего состояния (или природы в данном случае) этого объекта!

Для всех, кто интересуется пониманием того, как на самом деле решить эту проблему, я предлагаю изучить "Гибкие принципы" Роберта Мартина. Эта книга описывает разработку / внедрение реальной системы начисления заработной платы...

Другие вопросы по тегам