Coding Gun

หัดเขียน OOP ด้วย Python

ไม่ว่าคุณจะเขียนโปรแกรมภาษาอะไรก็ตาม Object Oriented Programming(OOP) จะเป็นสิ่งที่ต้องทำความเข้าใจและใช้งานให้ถูกต้อง ในบทความนี้ผมจะพาคุณไปรู้จักกับ การเขียน OOP ด้วย Python

Class vs Object

สิ่งแรกที่ต้องรู้จักก็คือ Class และ Object ความแตกต่างของ Class และ Object คือ

ตัวอย่าง เช่น เรามี Class ที่ชื่อว่า Duck มี property อยู่ 2 ตัวคือ _sound และ _movement

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Duck:
    _sound = 'Quack Quack'
    _movement = 'Walk like a duck'

    def quack(self):
        print(self._sound)

    # เราต้องใส่ self ไว้เสมอแต่ตอนเรียกใช้งานให้ข้ามไปได้เลย
    def move(self):
        print(self._movement)

สังเกตุว่า function ที่ประกาศอยู่ใน class จะต้องมี parameter ตัวแรกเป็น self ซึ่งจะเหมือนกับ this ในภาษาอื่นๆ

เวลานำ class ไป instantiating(สร้าง Object ขึ้นมาใช้งาน) เราจะเขียนแบบนี้

donald = Duck()
print(donald._sound)
# ตอนเรียก method move ไม่ต้องใส่ self
donald.move()

การใช้งาน Constructor

ใน Python จะมี default constructor มาให้อยู่แล้ว จากตัวอย่างที่แล้ว จะเห็นว่าเราสามารถสร้าง object ขึ้นมาได้เลย โดยที่ไม่ต้องมี constructor ส่วนถ้าคุณต้องการสร้าง constructor ขึ้นมาเองโดยใช้ method init โดยเราจะสามารถใส่ parameters เข้ามาได้แบบนี้

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Duck:
    def __init__(self, type):
        self.type = type

    def get_type(self):
        return self.type

def main():
    donald = Duck('Dog')
    print(f"I'm a {donald.get_type()}")

if __name__ == '__main__': main()

เราสามารถ รับ parameters หลายๆตัวได้ โดยที่ต้องเปลี่ยน parameters ใน init() เป็น **args และตอนสร้าง object ต้องใส่ชื่อ argument ด้วย(บรรทัดที่ 9)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Duck:
    def __init__(self, **args):
        self.type = args['type']

    def get_type(self):
        return self.type

def main():
    donald = Duck(type='Dog')
    print(f"I'm a {donald.get_type()}")

if __name__ == '__main__': main()

Access Modifier

ใน Python จะไม่มี access modifier(public, private) แบบภาษาอื่นๆ เพราะ python ต้องการความง่ายในการเขียน ดังนั้นเราะไม่ได้เขียน getter และ setter เหมือนกับภาษาอื่นๆ แต่เราจะใช้ “_” นำหน้าตัวแปร เช่นเปลี่ยนจาก type เป็น _type แล้วทุกคนที่เขียน python จะรู้กันว่าตัวแปร _type นี้เป็น private ถ้าคุณเรียก _type ตรงๆผลลัพธ์ที่ได้อาจไม่ตรงกับที่คุณคาดคิด

เปลี่ยน method ให้เป็น property ด้วย @Property

เหมือนกับ getter ในภาษาอื่นๆ ใน python เมื่อเราใส่ annotation @Property ไว้บน method ไหน เราจะสามารถเรียกแบบ property ได้เลยแบบในบรรทัดที่ 11

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Duck:
    def __init__(self, type):
        self._type = type

    @property
    def type(self):
        return self._type

def main():
    donald = Duck(type='Dog')
    print(f"I'm a {donald.type}")

if __name__ == '__main__': main()

เราสามารถสร้าง setter ได้ด้วย @[property_name].setter

ถ้าต้องการสร้าง setter เราจะใช้ชื่อ property แล้วตามด้วย .setter เช่นในตัวอย่างนี้เราต้องการ setter ของ type เราจะใช้ annotation ชื่อ @type.setter ในบรรทัดที่ 6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Duck:
    @property
    def type(self):
        return self._type

    @type.setter
    def type(self, type):
        if type not in ['Dabbling', 'Diving']:
            raise AttributeError("Duck type should be Diving or Diving")
        self._type = type

def main():
    donald = Duck()
    donald.type = 'Diving'
    print(f"I'm a {donald.type} Duck")

if __name__ == '__main__': main()

ตัวอย่างนี้เราจะทำ input validation แบบง่ายๆ โดยในบรรทัดที่ 8 เราจะเช็คว่า type เป็น Dabbling หรือ Diving รึเปล่า ถ้าไม่ใช้ จะมีการ throw exception ออกมาในบรรทัดที่ 9 ดังนั้นเราจะ set type ได้แค่ Dabbling หรือ Diving เท่านั้น ถ้าใส่อย่างอื่นเข้ามาจะ error

ความสัมพันธ์แบบ Inheritance

การ inherit จะเป็นความสัมพันธ์แบบ Is-a ซึ่งมีความสัมพันธ์ที่ class ลูกจะเป็น(is-a) class แม่ เช่น ในตัวอย่างนี้ เป็นเป็นสัตว์(Duck is-a Animal)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Animal:
    pass

# Duck inherit จาก Animal
# Duck is a animal
class Duck(Animal):
    pass

def main():
    donald = Duck()

if __name__ == '__main__': main()

Association

การสร้างความสัมพันธ์ระหว่าง class จะเป็นความสัมพันธ์แบบ Has_a เช่น ใน Company มี Employee เป็นต้น

เราสามารถระบุความสัมพันธ์ได้ 2 รูปแบบคือ

  1. Composition ความสัมพันธ์แบบเป็นส่วนประกอบของ ซึ่งหมายความว่าจำเป็นต้องมี ซึ่งในตัวอย่างนี้เราจะกำหนดให้ Company ต้องมี Employee อย่างน้อย 1 คนถึงจะทำงานได้ ดังนั้นความสัมพันธ์ของ Company และ Employee จะเป็น Composition

    จำง่ายๆว่า Composition ใส่ใน Constructor (เป็นตัว C เหมือนกัน)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    class Company:
        def __init__(self, employee):
            self.employees = [employee]
    
        def displayAllEmployees(self):
            for employee in self.employees:
                print(f'{employee._firstname} {employee._lastname}')
    
    class Employee:
        _firstname = ""
        _lastname = ""
    
    def main():
        employee1 = Employee()
    
        employee1._firstname = 'John'
        employee1._lastname = 'Doe'
    
        company1 = Company(employee1)
        company1.displayAllEmployees()
    
    
    if __name__ == '__main__': main()
    
  2. Association เป็นความสัมพันธ์แบบที่เบาบางลง(เอาไป reuse ได้ง่ายขึ้น) เราจะสร้าง object ขึ้่นมาแบบต่างคนต่างอยู่และมาทำความรู้จักกันทีหลัง

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    class Company:
        employees = []
    
        def addEmployee(self, employee):
            self.employees.append(employee)
    
        def displayAllEmployees(self):
            for employee in self.employees:
                print(f'{employee._firstname} {employee._lastname}')
    
    class Employee:
        _firstname = ""
        _lastname = ""
    
    def main():
        employee1 = Employee()
    
        employee1._firstname = 'John'
        employee1._lastname = 'Doe'
    
        company1 = Company()
        company1.addEmployee(employee1)
        company1.displayAllEmployees()
    
    
    if __name__ == '__main__': main()
    

    ในตัวอย่างนี้เราจะสร้าง object employee1 และ company1 ในบรรทัดที่ 16 และ 21 ตามลำดับ หลังจากนั้นทั้ง 2 object นี้จะมารู้จักกันด้วย method addEmployee ในบรรทัดที่ 22 ซึ่งในกรณีนี้เป็นความสัมพันธ์แบบ Association(Company สามารถอยุ่ได้โดยที่ไม่มี Employee)

Phanupong Permpimol
Follow me