2016-12-14 1 views
3

저는 downcast 참조 변수뿐만 아니라 Polymorphism 주제의 Java 책을 읽었습니다. 그러나, 나는 downcasting의 개념을 이해하는 것에 꽤 빠져있다. 다음은 제가 따르는 예제의 uml입니다. 자신의 기본급에 10 %의 증가를 주어진에 그들이 BasePlusCommissionEmployee의 모든 개체다형성 및 다운 캐스팅 질문

UML

. 다른 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 대한 개선 및 각 반복에서 상기 어레이의 상이한 Employee에 대한 참조를 할당 Employee 변수 currentEmployee와 방법을 toStringearnings을 호출한다고 설명한다. 결과적으로, 출력은 각 클래스의 특정 메소드가 호출되고 오브젝트 유형에 따라 실행 시간에 해석되는 것을 보여줍니다. BasePlusCommissionEmployee의 방법 getBaseSalary 현재 Employee 개체 setBaseSalary를 호출하기 위해

는 조건문은 객체 참조는 instanceof 연산자 및 경우를 이용하여 BasePlusCommissionEmployee 객체 조건이 사실 인 경우 확인하는 데 사용 객체는 언급 된 방법을 호출하기 전에 다운 케스트에서 Employee to BasePlusCommissionEmployee 유형이어야합니다.

이 심각하게 우리가 서브 클래스 'toString 방법에 액세스 할 수 있기 때문에 저를 혼란스럽게하지만, 다른 방법, 즉 getBaseSalarysetBaseSalary를 사용하기 위해 객체를 다운 캐스트 할 수있다? 왜 이런 경우입니까?

답변

3

toString()Object에 정의되어 있으므로 모든 클래스에서 사용할 수 있습니다. 기본 급여에 대한 getter와 setter는 BasePlusCommissionEmployee에서만 사용할 수 있으므로 Employee 참조 (다른 유형을 나타내는 경우 어떻게됩니까?)를 통해 호출 할 수는 없습니다.

이 예제는 실제 코드에서 볼 수있는 것이 아닙니다. instanceof를 사용하여 수행 할 작업을 결정할 때 스타일이 잘못되었습니다.

+0

그래 나에게 너무 많은 의미가 있습니다. 그런데 왜 instanceof를 사용하는 것이 나쁜 습관이라고 말합니까? – Scorpiorian83

+0

instanceof는 일반적으로 다형성을 적용하는 코드로 대체 할 수 있기 때문에 좋지 않습니다. GhostCat의 답변을 참조하십시오. 다시 말해서 : if (obj instanceof ClassA) {doA(); } else if (클래스 B의 obj 인스턴스) {doB(); }'ClassA와 ClassB의 수퍼 클래스에서'doStuff()'메소드를 정의하고 각 클래스에서 그것을 오버 라이딩하여 올바른 일을 한 다음 위의 코드를'obj.doStuff()'로 바꾸면 더 낫습니다. –

1

내 눈에 더 가치가 있음 : 실제로는 다소 불량 예입니다.

다운 캐스트은 종종 잘못된 디자인을 나타냅니다. 여기이 규칙을 잘 증명하고 있습니다.

Payroll 시스템이 이 아니어야합니다.은 그러한 "instanceof"점검이 필요합니다. 그런 다음 특정 하위 클래스에 대한 특정 계산을 수행합니다. 다형성을 이용하는 전체 점이다

: 그 다른 클래스와 BasePlusCommissionEmployee CommissionEmployee 각 정확하게 올바른 급여 계산하기위한 수단을 포함한다.

여기서 유지해야 할 것은 TDA (tell dont ask) 원리입니다.좋은 객체 지향은 객체에 "do thing"을 말합니다. 그 객체의 내부 상태 (또는이 경우 자연)에 기반하여 외부 결정을 내리십시오!

을 이해하는 데 관심이있는 사람이라면 누구나이이 문제를 해결하기 때문에 Robert Martin의 "민첩한 원칙"을 살펴볼 것을 제안합니다. 그 책은 실제 급여 시스템의 설계/구현에 대해 설명합니다 ...

+0

귀하의 지식에 대해 대단히 감사 드리며 애자일 원칙을 배우고 환호성을 보일 것입니다. – 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 선언 된 유형에 대한 방법을 제공 basePlusCommissionEmployee.getBaseSalary() 때문이다.

당신은 또한 수행 할 수 있습니다 방법은 Object 클래스의 public 메소드는 모든 클래스가 Object 클래스에서 상속, 그래서이 클래스는 toString()을 가지고 있기 때문에 두 가지 유형 (EmployeeBasePlusCommissionEmployee가) toString()하는 방법을 제공 basePlusCommissionEmployee.toString()currentEmployee.toString() 때문에 방법.

currentEmployee.getBaseSalary() 신고 된 유형은 Employee이므로이 방법을 제공하지 않으므로 수행 할 수 없습니다.

을 무시하려면 대상 하위 클래스에 기본 클래스에서 다운 캐스트 할 수 있습니다 : 당신이 말한 것을

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

다윗에게 저에게 설명 할 소중한 시간을 가져 주셔서 감사합니다. 나는 마침내 그 이유를 이해합니다. 그러나 마지막 코드 줄을 보았을 때, 그것을 처음 보았습니다. 그게 무슨 뜻인지 물어봐도 될까요? 이것에 대한 용어가 있습니까? – Scorpiorian83

+0

당신은 천만에요.잘 이해했다 :) 마지막 줄은 메서드를 호출하기 위해 개체를 캐스팅 할 때 바로 가기이지만 캐스트의 결과를 매개 변수에 저장할 필요가 없습니다. 아마도 여러분을 방해하는 전역 괄호 일 수 있습니다. 'BasePlusCommissionEmployee' 형 인스턴스에'getBaseSalary()'메소드를 적용 할 수 있습니다. '(BasePlusCommissionEmployee) currentEmployee.getBaseSalary()'만 쓰면'getBaseSalary()'가'currentEmployee' 변수에 적용되기 때문에 컴파일 오류가 발생합니다. 봐. – davidxxx

+0

. 시원한. 다시 형제님께 감사드립니다! – Scorpiorian83