Python – OOP(Object-Oriented Programming)

สำหรับ python นั้นภาษาหนึ่งที่รองรับรูปแบบการเขียนโปรแกรมหลายกระบวนทัศน์(multi-paradigm programming language) หรือถ้าให้เรียกง่ายๆ ก็คือรองรับรูปแบบการเขียนโปรแกรมในหลายรูปแบบ(อ่านเพิ่มเติมเกี่ยวกับกระบวนทัศน์) ซึ่งจะสามารถใช้การเขียนโปรแกรมในหลายรูปแบบ ซึ่งคุณลักษณะหนึ่งที่รับมาใช้งานก็คือ รูปแบบการเขียนโปรแกรมแบบหนึ่งที่เป็นที่นิยมกันมากในปัจจุบันคือ การเขียนโปรแกรมเชิงวัตถุ หรือ OOP(Object-Oriented programming language)

การเขียนโปรแกรมในรูปแบบเชิงวัตถุนั้น จะให้ความสำคัญกับวัตถุจะเป็นการจัดแบ่งส่วนประกอบต่างๆในโปรแกรมให้เป็นวัตถุ (object) โดยวัตถุจะสามารถดำเนินการต่างๆ ได้, เก็บข้อมูลต่างและสื่อสารเพื่อแลกเปลี่ยนข้อมูลระหว่างกันและ

โดยวัตถุหนึ่ง(object)หนึ่งจะประกอบด้วยลักษณะสำคัญ 2 ประการ คือ:
– คุณลักษณะ(attributes) สำหรับเก็บข้อมูลต่างๆที่เกี่ยวข้องกับวัตถุนี่
– พฤติกรรม(behavior) เป็นการดำเนินการของวัตถุนี่ อาจจะใช้เพื่อคำนวนต่างๆ หรือส่งข้อมูลไปมา

ตัวอย่างเช่น
เรากำหนดให้สร้างวัตถุชนิดหนึ่ง(object)แทน การทำงานเกี่ยวกับรถยนต์ ซึ่งภายในวัตถุนี้มีลักษณะสำคัญตามหัวข้อข้างต้นดังนี้
คุณลักษณะ(attributes) ของรถยนต์ ประกอบด้วย: สี, ชนิด, จำนวนล้อ, ความยาว, ความกว้าง, ความสูง
พฤติกรรมของรถยนต์(behavior) ประกอบด้วย: เคลื่อนไปข้างหน้า, ถอยไปข้างหลัง, เลี้ยว, จอด

เราใช้งาน OOP เพื่อที่สามารถจะช่วยให้ไม่มีการเขียนกลุ่มคำสั่งใดๆ ซ้ำซ้อน ซึ่ง concept นี้รู้จักกันในอีกชื่อหนึ่งว่า DRY(Don’t repeat yourself)

คลาส(class)
คลาสเป็น blueprint สำหรับออบเจ็ค สำหรับระบุโครงร่างของสิ่งใดๆ วัตถุนั้น เช่นรถยนต์ โดยจะบรรจุมี ข้อมูลเช่น สี, ชนิด, จำนวนล้อ, ความยาว, ความกว้าง, ความสูง โดยจากข้อมูลดังกล่าว เราสามารถรู้จักคุณลักษณะของรถยนต์แต่ละคันได้จากข้อมูลเหล่านี้
ตัวอย่างการใช้งาน

class Car:
     pass

จากตัวอย่าง เราใช้คีย์เวิร์ดคลาสเพื่อสร้างคลาสเปล่าสำหรับไว้ระบุข้อมูลเกี่ยวกับรถยนต์ และจากคลาสนี้เราจะนำไปสร้าง instance ซึ่งจะไว้ระบุข้อมูลรถยนต์ในแต่ละคันซึ่งมีความแตกต่างกันในแต่ละคันตามข้อมูลของคุณลักษณะ

ออบเจ็ค(Object)
โดยออบเจ็ค(instance) คือ คลาส วัตถุที่ถูกสร้างขึ้นจากคลาสและระบุคุณลักษณะเฉพาะสำหรับสิ่งนั้นๆ โดยเมื่อเราเขียนรายละเอียดของคลาสเรายังไม่ใช้หน่วยความจำใดๆ ในการเก็บข้อมูล แต่เมื่อทำการสร้างออบเจ็ค(instance) จะมีการใช้หน่วยความจำในการเก็บข้อมูลลักษณะเฉพาะของรถยนต์แต่ละคัน
ตัวอย่างการใช้งาน

class Car:
     pass

myCar = Car()

จากตัวอย่าง myCar เป็น instance ของคลาส Car

ส่วนต่อไปเราจะทำการระบุคุณลักษณะของรถยนต์

class Car:
     string color
     string type
     int wheels
     int width
     int length
     int height
     int position
     def __init__(self, color, type, wheels, width, length, height):
          self.position = 0
          self.color = color
          self.type = type
          self.wheels = wheels
          self.width = width
          self.length = length
          self.height = height

myCar = Car("white", "truck", 6, 1.5, 2, 1.5)
annieCar = Car("red", "van", 4, 1.2, 1.5, 1.5)

print("my car is: {} current position is: {}".format( myCar.__class__.color, myCar.__class__.position) )
print("annie's car is: {} current position is: {}".format( annieCar.__class__.color, annieCar.__class__.position) )

ผลที่ได้

my car is: white current position is: 1
my car is: red current position is: 5

จากตัวอย่างเราได้ทำการสร้างคลาสสำหรับรถยนต์ ชื่อ Car และมีคุณลักษณะข้อมูลไว้สำหรับอธิบายลักษณะของรถยนต์คือ สี(color), ชนิด(type), จำนวนล้อ(wheels), ความกว้าง(width), ความยาว(length), ความสูง(height)

จากนั้นเราทำการสร้าง instance ของคลาสก็คือ myCar และ annieCar เพื่อไว้อธิบายคุณลักษณรถของฉัน และรถของแอนนี่

จากนั้นเราจึงเข้าถึงข้อมูลคุณลักษณะของรถยนตร์โดยใช้ __class__.color, myCar.color โดยคุณลักษณะทั้งหมดที่สามารถระบุได้จะเหมือนกันหมดสำหรับทุก instance ของคลาสชนิดเดียวกัน แต่เราสามารถระบุข้อมูลให้คุณลักษณะดังกล่าวให้แต่ละ instance มีความแตกต่างกันได้

เมธทอด(method)
เมธทอดคือฟังก์ชันที่ระบุภายใน body ของคลาส ใช้เพื่อการทำงานของออบเจ็ค
ตัวอย่างการใช้งาน

class Car:
     pass

myCar = Car()

จากตัวอย่าง myCar เป็น instance ของคลาส Car

ส่วนต่อไปเราจะทำการระบุคุณลักษณะของรถยนต์

class Car:
     string color
     string type
     int wheels
     int width
     int length
     int height
     int position
     def __init__(self, color, type, wheels, width, length, height):
          self.position = 0
          self.color = color
          self.type = type
          self.wheels = wheels
          self.width = width
          self.length = length
          self.height = height

     def stop(self):
          pass

     def go_foward(self, step):
          self.position += step

     def go_backward(self, step):
          self.position -= step

myCar = Car("white", "truck", 6, 1.5, 2, 1.5)
annieCar = Car("red", "van", 4, 1.2, 1.5, 1.5)

myCar.go_foward(2)
myCar.go_backward(1)

annieCar.go_backward(5)
annieCar.go_foward(10)

print("my car is: {} current position is: {}".format( myCar.__class__.color, myCar.__class__.position) )
print("annie's car is: {} current position is: {}".format( annieCar.__class__.color, annieCar.__class__.position) )

ผลที่ได้

my car is: white current position is: 1
my car is: red current position is: 5

จากตัวอย่าง เราได้ทำการกำหนด 3 เมธทอด ก็คือ stop, go_foward, go_backward สำหรับการหยุด, เดินหน้า และถอยหลัง ซึ่งเมทธอดนี้จะเรียกว่า instance method และสามารถเรียกใช้ได้จาก instance ของ class ซึ่งก็คือ myCar, annieCar

สำหรับ Python การใช้ OOP นั้นมีหลักการพื้นฐานดังนี้
Inheritance: เป็นการสืบทอดคุณลักษณะจากคลาสเดิมมาสู่คลาสใหม่ โดยไม่มีการแก้ไขข้อมูลในคลาสเดิม
Encapsulation: เป็นการป้องกันข้อมูลบางส่วนสำหรับคลาสหนึ่ง ให้ไม่สามารถเรียกใช้จากคลาสอื่นๆ
Polymorphism: เป็นการสร้างการดำเนินการใดๆ แบบเดียวกันในหลายๆแบบโดยขึ้นอยู่กับข้อมูลที่ถูกส่งเข้ามา

การสืบทอด(inheritance)
การสืบทอดเป็นวิธีการสร้างคลาสใหม่โดยจะใช้คุณลักษณะหรือเมทธอดที่มีอยู่ในคลาสเดิมๆ โดยไม่ทำการเปลี่ยนแปลงคุณลักษณะเหล่านั้น โดยจะเรียกคลาสใหม่นี้ว่า derived class หรือ child class และคลาสต้นแบบนั้นคือ base class หรือ parent class

class Car:
     string color
     string type
     int wheels
     int width
     int length
     int height
     int position
     def __init__(self, color, type, wheels, width, length, height):
          self.position = 0
          self.color = color
          self.type = type
          self.wheels = wheels
          self.width = width
          self.length = length
          self.height = height

     def stop(self):
          pass

     def go_foward(self, step):
          self.position += step

     def go_backward(self, step):
          self.position -= step

class AutonomousCar(Car):
     def __init__(self, color, type, wheels, width, length, height):
          super().__init__(color, type, wheels, width, length, height)
          
     def camera_read():
          print("read image data from camera")

     def sensor_read():
          print("read sensor data from sensor")

myCar = AutonomousCar("white", "autonomous", 6, 1.5, 2, 1.5)
myCar.camera_read()
myCar.sensor_read()
myCar.go_foward(2)
myCar.go_backward(1)

จากตัวอย่าง เราทำการสร้างคลาส Car ซึ่งเป็นคลาสต้นแบบ(Parent class) และสร้างคลาส AutonomousCar ซึ่งเป็นคลาสที่สืบทอด(inherit)คุณลักษณะและฟังก์ชันมาจากคลาส Car ซึ่งเมทธอดและคุณลักษณะต่างๆในคลาส Car ก็ยังสามารถจะใช้งานได้ในคลาส AutomousCar นอกจากนี้เรายังได้ทำการเพิ่มเมทธอดใหม่เข้าไปในคลาส AutonomousCar ที่สามารถทำงานได้นอกเหนือจากที่มีในรถยนต์ทั่วไปได้

Encapsulation
เราสามารถจำกัดการเข้าถึงเมทธอดและคุณลักษณะต่างๆ ด้วย encapsulation เพื่อไม่ให้มีการทำการแก้ไขข้อมูลบางชนิดโดยตรง โดยเราจะใช้เครื่องหมาย _ หรือ __ เป็น prefix สำหรับการระบุให้เป็น private

class Car:
     string color
     string type
     int wheels
     int width
     int length
     int height
     int position
     def __init__(self, color, type, wheels, width, length, height):
          self.__position = 0
          self.color = color
          self.type = type
          self.wheels = wheels
          self.width = width
          self.length = length
          self.height = height

     def stop(self):
          pass

     def go_foward(self, step):
          self.__position += step

     def go_backward(self, step):
          self.__position -= step

     def distance():
          print("total distance: {}".format(self.__position))


car = Car("white", "autonomous", 6, 1.5, 2, 1.5)
self.__position = 8
car.distance()
car.go_foward(5)
car.go_foward(5)
car.distance()
car.go_backward(1)
car.distance()

ผลที่ได้

total distance: 0
total distance: 10
total distance: 9

จากตัวอย่าง เราได้กำหนดตัวแปร position เพื่อเก็บตำแหน่งที่เดินทาง โดยมีการกำหนดให้ค่าเป็น private ด้วยเครื่องหมาย __ ดังนั้น เมื่อเราทำการกำหนดค่าด้วย self.__position เนื่องจากค่าดังกล่าวเป็น private จึงไม่สามารถเปลี่ยนแปลงข้อมูลได้ตำแหน่งจึงออกมาที่ 0 แต่เมื่อเราทำการเปลี่ยนแปลงค่าด้วยเมทธอด go_foward หรือ go_backward ซึ่งอ้างถึงข้อมูลภายในแล้วทำการเปลี่ยนแปลงค่า จึงจะสามารถเปลี่ยนแปลงข้อมูลตำแหน่งดังกล่าวได้ถูกต้อง


Polymorphism

เราสามารถใช้เมทธอดชื่อเดียวกันแต่ดำเนินการกับข้อมูลต่างชนิดกันได้ ซึ่งเรียกวิธีการนี้ว่า polymorphism ตัวอย่างเช่น หากเราต้องการลงสีให้กับรูปร่างแบบหนึ่ง โดยที่รูปร่างนั้น อาจจะมีได้หลายแบบเช่น วงกลม, สี่เหลี่ยม หรือสามเหลี่ยม เราสามารถใช้ชื่อเมทธอดเดียวแต่ลงสีให้กับรูปร่างที่ต่างกันเหล่านี้ได้

class Car:
     string color
     string type
     int wheels
     int width
     int length
     int height
     int position
     def __init__(self, color, type, wheels, width, length, height):
          self.position = 0
          self.color = color
          self.type = type
          self.wheels = wheels
          self.width = width
          self.length = length
          self.height = height

     def stop(self):
          pass

     def go_foward(self, step):
          self.position += step

     def go_backward(self, step):
          self.position -= step

class ManualCar(Car):
     def gear_up():
          pass

     def gear_down():
          pass

class AutonomousCar(Car):
     def __init__(self, color, type, wheels, width, length, height):
          super().__init__(color, type, wheels, width, length, height)
          
     def camera_read():
          print("read image data from camera")

     def sensor_read():
          print("read sensor data from sensor")

def stop_car(car):
     car.stop()

autonomousCar = AutonomousCar("white", "autonomous", 6, 1.5, 2, 1.5)
manualCar = ManualCar("white", "manual", 6, 1.5, 2, 1.5)
stop_car(autonomousCar)
stop_car(manualCar)

จากตัวอย่าง เราสร้างออบเจ็คจากคลาส ManualCar และ AutonomousCar โดยทั้งสองคลาสนั้นมีเมทธอด stop เหมือนกัน(ควรหาฟังก์ชันที่ใช้งานต่างกัน) ดังนั้นจากฟังก์ชัน stop_car ซึ่งรับออบเจ็คที่เป็นชนิด Car แบบใดก็ได้โดยอาศัยหลักการของ polymorphism
เมื่อเราส่ง instance autonomousCar เข้าไปแล้วสั่งให้รันเมทธอด stop โปรแกรมก็จะทำงานแบบหนึ่ง แต่เมื่อเราส่ง instance manualCar เข้าไปแล้วสั่งให้รันเมทธอด stop โปรแกรมก็จะทำงานในอีกรูปแบบหนึ่ง ขึ้นอยู่กับรายละเอียดในฟังก์ชัน stop ที่เราได้ระบุไว้ในคลาสนั้นๆ