14. 繼承 - 多型

多型(polymorphism)是指使用相同的函式,可以操作在不同型態的實體上。完成多型最基本的要求是這些不同型態的實體都有相同名稱的方法,為了完成此要求,讓它們都繼承相同的抽象類別是一種確保大家都有某些方法的實作方式。

(1) 「一般職員」和「兼任職員」繼承了抽象的「職員」

from abc import ABC, abstractmethod

#----------------------
# 父類別, 職員(抽象)
#----------------------
class Employee(ABC):        
    def __init__(self, no, name):
        self.__no = no
        self.__name = name
          
    @property
    def no(self):
        return self.__no
    
    @property
    def name(self):
        return self.__name
    
    @no.setter
    def no(self, no):
        self.__no = no
        
    @name.setter
    def name(self, name):
        self.__name = name

    # 計算薪水的抽象方法            
    @abstractmethod
    def salary(self):
        return NotImplemented

#----------------------
# 子類別, 一般職員
#----------------------    
class RegularEmployee(Employee):
    def __init__(self, no, name, overtimes):
        super().__init__(no, name)
        self.__overtimes = overtimes
        
    @property
    def overtimes(self):
        return self.__overtimes    
    
    @overtimes.setter
    def overtimes(self, overtimes):
        self.__overtimes = overtimes
    
    #具體化計算薪水的方法
    def salary(self):
        return 50000 + self.overtimes*250
    
#----------------------
# 子類別, 兼職職員
#----------------------    
class ParttimeEmployee(Employee):
    def __init__(self, no, name, period, hours):
        super().__init__(no, name)
        self.__period = period
        self.__hours = hours
        
    @property
    def period(self):
        return self.__period    
    
    @property
    def hours(self):
        return self.__hours
    
    @period.setter
    def period(self, period):
        if period not in ('日班', '夜班'):
            raise ValueError('班別資料有誤!')
        else:
            self.__period = period
        
    @hours.setter
    def hours(self, hours):
        self.__hours = hours
    
    #具體化計算薪水的方法
    def salary(self):
        if self.period == '日班':
            return 235*self.hours
        elif self.period == '夜班':
            return 295*self.hours

第28~30行用@abstractmethod宣告一個計算薪水的抽象方法。 第49~50行,完成一個一般職員的計算薪水方法。 第81~85行,完成一個兼職職員的計算薪水方法。

以下是一個使用它們的例子:

#--------------------------------
# 可接收一般職員或兼職職員實體
#--------------------------------        
def info(e):
    print(e.no)
    print(e.name)
    print(f'{e.salary():,}元') 
       
#----------------------------------------
emp = []
emp.append(RegularEmployee('1001', '王小明', 20))
emp.append(ParttimeEmployee('1002', '陳小華', '日班', 65))

for e in emp:      
    info(e)

第4~7行的函式可接收不同型態的職員,如果傳入一般職員,第7行的salary()執行一般職員的公式;如果傳入兼職職員,就執行兼職職員的公式。同一段程式可執行不同的程式碼,稱為多型。

執行結果:

1001 王小明 55,000元 1002 陳小華 15,275元

說明:

問題:

請以以上的例子為基礎,再增加1個「海外職員」類別,名稱是「OverseasEmployee」。「海外職員」也繼承「職員」,它有1個建構元以設定「派外國家」,它也要完成salary()方法,用來計算薪水。計算的方法是「派至美國薪水80,000元,其他國家75,000元」。

請產生「一般職員」、「兼職職員」、「海外職員」實體,存在同一個清單中,呼叫同一個函式,以多型的特性印出不同員工的薪水。