Go ไม่มี class และ object แต่ทำไมถึงมี Method

Go ไม่มี class แต่ทำไมถึงมี Method

ก่อนจะว่าด้วยเรื่อง Method ไปดูเรื่อง Function กันก่อน Function ของ Go ก็แบบเดียวกับภาษาอื่นๆอย่างเช่น C นั่นล่ะครับ ตัวอย่างเช่น

func sayHello() {
        fmt.Println(“Hello”)
}

Function ก็สามารถรับค่า และ return ค่ากลับได้เช่น

func add(a, b int) int {
        return a+b
}

ต่อไปถ้าผมสร้าง type struct ขึ้นมาสักตัวเช่นผมไปลอก class Bicycle จาก Java Tutorial http://docs.oracle.com/javase/tutorial/java/javaOO/classes.html มาทำเป็น type Bicycle struct ดังนี้

type Bicycle struct {
        cadence int
        gear int
        speed int
}

ทีนี้ถ้า Go เป็นแค่ภาษาที่มี Function เราอยากสร้าง Function ที่เพิ่ม และ ลด speed ของข้อมูลแบบ Bicycle ขึ้นมา เราสามารถสร้าง function ได้ประมาณนี้

func SpeedUp(b *Bicycle, increment int) {
        b.speed += increment
}

นั่นคือเราต้องส่งค่า pointer ของ Bicycle เข้าไป ถามว่าทำไมต้องเป็น pointer ก็เพราะว่าเราจะเราต้องเปลี่ยนค่าของ arguments ที่ส่งเข้าไปได้ ถ้าเรารับเป็น Bicycle ไม่ใช่ pointer ของ Bicycle จะเป็นการ copy ไม่ใช่การอ้างอิง จะเปลี่ยนค่าของต้นฉบับไม่ได้นั่นเอง

อีกตัวอย่าง Function ลดความเร็ว ทำได้แบบนี้

func ApplyBrake(b *Bicycle,decrement int ) {
        b.speed -= decrement
}

ถามว่าถ้าเราไม่ได้อยากเปลี่ยนแปลงค่าของ Bicycle แค่อยากใช้ข้อมูลที่มีข้างใน ไม่ต้องเป็น pointer ได้มั้ย ได้เลยครับ เช่น

func String(b Bicycle) string {
        return fmt.Sprintf(“cadence : %d, gear : %d, speed : %d”, b.cadence, b.gear, b.speed)
}

จากตัวอย่าง 3 Funcitons เนี่ย เราต้องการทำอะไรบางอย่างกับข้อมูลแบบ Bycycle หมดเลย

ทีนี้ก่อนจะไปเรื่อง Method ผมขอยกนิยามของ Object Oriented ของ Alan Kays (ผู้สร้างภาษา Smalltalk) จากเว็บนี้ http://c2.com/cgi/wiki?AlanKaysDefinitionOfObjectOriented
ทั้ง 6 ข้อมาให้ดูครับ ได้แก่

  1. EverythingIsAnObject
  2. Objects communicate by sending and receiving messages (in term of objects).
  3. Objects have their own memory (in term of objects).
  4. Every object is an instance of a class (which must be and object).
  5. The class holds the shared behaviour for its instances (in the form of objects in a program list)
  6. To eval a program list, control is passed to the first object and the remainder is treated as its message.

เราลองย้อนไปดูว่า object ในภาษา smalltalks ที่เป็นภาษา OOP ยุคแรกๆตัวนึงว่าเป็นยังไง Smalltaks บอกว่า Object เนี่ยสามารถทำได้ 3 สิ่งด้วยกันคือ

A Smalltalk object can do exactly three things:

  1. Hold state (references to other objects).
  2. Receive a message from itself or another object.
  3. In the course of processing a message, send messages to itself or another object.

จะเห็นว่า OOP ยุคแรกๆ โดยเฉพาะ Smalltalks พูดถึงในมุมการสื่อสารกันระหว่าง object มากกว่าการสนใจว่า Object แทนวัตถุในโลกจริงๆ จริงๆแล้ว OOP แทนที่เราจะเรียกว่าการเขียนโปรแกรมเชิงวัตถุ เป็นการเขียนโปรแกรมเชิงการสื่อสารก็ยังได้ :D

กลับมายัง Function SpeedUp, ApplyBrake และ String ของเราที่เขียนไปก่อนหน้านี้กันอีกครั้ง ในมุมของการทำงานของโปรแกรม การเรียก Function ก็คือการสื่อสารอย่างหนึ่งเช่นกัน เช่น

b := new(Bicycle)

ถ้าเราต้องการให้ b ทำการ SpeedUp ไป 10 ทำได้แบบนี้

SpeedUp(b, 10)

ถ้าเราต้องการให้ b แปลงเป็น String ทำได้แบบนี้

fmt.Println(String(*b))

ถ้าเราต้องการให้ b ทำการลดความเร็วลงมา 10 ทำได้แบบนี้

ApplyBrake(b, 10)

จะเห็นว่าเป็นการสั่ง (ส่งข้อความ) เจาะจงไปที่ b ในที่นี้ b ก็กลายเป็นคนโดนสั่ง (รับข้อความ (receiver))

อ่าาาา เห็นมั้ยว่าแม้จะมีแค่ Function ก็เขียนให้เข้านิยามของ object และ การส่ง message ของ OOP ได้เช่นกัน

แล้วทำไมต้องมี method? มันมีสาเหตุ เดียวจะว่าตอนถัดไป (สปอย *เกี่ยวกับ interface) มาดูก่อนว่าทีนี้ถ้าเขียนทั้ง 3 ฟังก์ชันนั้นในรูปแบบ method เขียนได้อย่างไร

เวลาเขียน method ของ Go จะเขียนเหมือน Function แต่เราจะเพิ่มส่งกำหนด receiver เอาไว้ก่อนชื่อ Function เช่น

func (b *Bicycle) SpeedUp(increment int) {
        b.speed += increment
}

func (b *Bicycle) ApplyBrake(decrement int) {
        b.speed += decrement
}

func (b  *Bicycle) String() string {
        return fmt.Sprintf(“cadence : %d, gear : %d, speed : %d”, b.cadence, b.gear, b.speed)
}

เท่านี้ก็ได้ method สำหรับ type Bicycle struct เรียบร้อยแล้ว ส่วนเรื่อง มันเขียนเป็น function ก็ได้ทำไมต้องมี method ลองกลับไปคิดกันเล่นๆนะครับ เดี๋ยวผมมาเล่าอีกทีตอนต่อไป :D