2016-12-14 3 views
3

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

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 

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

Для вызова методов getBaseSalary и setBaseSalary на текущем Employee объекта BasePlusCommissionEmployee «s, условие оператора используется для проверки, если ссылка на объект является BasePlusCommissionEmployee объектом, используя InstanceOf оператора и, если условие истинно, объект должен быть downcast от Employee до BasePlusCommissionEmployee тип перед вызовом упомянутых методов.

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

ответ

3

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

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

+0

да то, что вы сказали, делает так много смысла для меня. Кстати, почему бы вам сказать, что использование instanceof является плохой практикой? – Scorpiorian83

+0

instanceof - плохая практика, потому что она обычно заменяется кодом, применяющим полиморфизм. См. Ответ GhostCat. Иначе говоря: код 'if (obj instanceof ClassA) {doA(); } else if (obj instanceof ClassB) {doB(); } 'лучше писать путем определения метода' doStuff() 'в суперклассе ClassA и ClassB, переопределяя его в каждом классе, чтобы сделать правильную вещь, а затем заменив код выше на' obj.doStuff() '. –

1

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

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

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

Это все смысла использования полиморфизма: те, разные классы BasePlusCommissionEmployee и CommissionEmployee должны каждый содержат средства, чтобы правильно вычислить правильную зарплату.

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

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

+0

Большое вам спасибо за ваши знания, и я также пойду, чтобы получить Agile Principles и хорошо посмотреть на это. – Scorpiorian83

+0

@ Scorpiorian83 Подсказка: вы можете найти версию C# этой книги бесплатно ... и поскольку исходный код менее важен там (UML-диаграммы уверены, что язык не зависит) ... это то, что я читаю первым. – GhostCat

+0

Еще раз спасибо, что я только что закончил загрузку книги. : D – Scorpiorian83

2

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

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

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(); 
+0

спасибо Дэвиду за то, что вы потратили свое драгоценное время, чтобы объяснить мне. Я, наконец, понимаю, почему, но что касается последней строки кода, которую вы мне показали, я впервые вижу это. Могу я спросить, что это значит? Есть ли для этого термин? – Scorpiorian83

+0

Добро пожаловать.Отлично вы поняли :) Последняя строка - это ярлык, когда вы хотите, чтобы объект вызывал метод, но вам не нужно сохранять результат приведения в промежуточной переменной. Возможно, это мешает вам глобальная скобка. он позволяет применять метод 'getBaseSalary()' в экземпляре 'BasePlusCommissionEmployee'. Если вы пишете только '(BasePlusCommissionEmployee) currentEmployee.getBaseSalary()', у вас будет ошибка компиляции, потому что 'getBaseSalary()' будет применяться к переменной currentEmployee. – davidxxx

+0

я вижу. круто. Еще раз спасибо! – Scorpiorian83

 Смежные вопросы

  • Нет связанных вопросов^_^