Golang — Open-Closed Principle

S.O.L.I.D คือ principles 5 อย่างสำหรับการเขียนโปรแกรมแบบ OOP แต่ในภาษา Go ไม่มี Class นิหน่า แล้วเราจะเอา principles ทั้ง 5 อย่างมาใช้ได้ยังไงกันนะ ?

ในบทความนี้ผมจะขอพูดถึง principle ตัวที่ 2 ของ S.O.L.I.D ซึ่งก็คือ Open-Closed Principle นะครับ xD

Open-Closed Principle คือการที่เราสร้าง Class, Function ฯลฯ ใด ๆ ขึ้นมา แล้วต้องเปิด (Open) ให้เพิ่มความสามารถได้ แต่ปิด (Closed) ไม่ให้ไปแก้ Class เดิม

ลองดูตัวอย่างง่าย ๆ นะครับ

เรามี MemoryWriter ทำหน้าที่เขียน string เข้าไปในหน่วยความจำ

type MemoryWriter struct {
close bool
data string
}
func (wr *MemoryWriter) Write(value string) {
if wr.close {
panic(errors.New("writer is closed"))
}
wr.data += value
}
func (wr *MemoryWriter) Close() {
wr.close = true
}

แล้วเรามี Function อันนึงที่จะเขียนข้อความ Hello ลง MemoryWriter แล้วก็ Close MemoryWriter ที่ส่งให้ function ตัวนี้

func writeHelloAndClose(wr *MemoryWriter) {
wr.Write("Hello")
wr.Close()
}

แล้วมี code ที่เรียกใช้แบบนี้

func main() {
wr := &MemoryWriter{}
writeHelloAndClose(wr)
fmt.Printf("wr: %s\n", wr.data)
}

คำถามคือ ถ้าเราต้องการเขียนข้อความต่อหลังจากเรียกคำสั่ง writeHelloAndClose จะต้องทำยังไงหล่ะ ?

แน่นอนว่าเราเขียนต่อไปเลยแบบนี้ไม่ได้แน่ ๆ

func main() {
wr := &MemoryWriter{}
writeHelloAndClose(wr)
wr.Write("other text") // panic
fmt.Printf("wr: %s\n", wr.data)
}

เพราะ MemoryWriter ถูก Close ไปแล้ว


เราสามารถแก้ปัญหานี้ได้โดยการนำ Open-Closed Principle มาใช้

โดยการสร้าง interface ขึ้นมาตัวนึง

type Writer interface {
Write(string)
Close()
}

แก้ writeHelloAndClose ให้รับ Writer interface แทน

func writeHelloAndClose(wr Writer) {
wr.Write("Hello")
wr.Close()
}

เรายังสามารถใช้ writeHelloAndClose แบบเดิมได้ เพราะว่า MemoryWriter ของเรา implement Writer interface อยู่แล้ว

func main() {
wr := &MemoryWriter{}
writeHelloAndClose(wr)
fmt.Printf("wr: %s\n", wr.data)
}

คราวนี้เราจะสร้าง struct มาอันนึง เป็น Writer ที่สั่ง Close แล้วไม่มีอะไรเกิดขึ้น

type NoCloseWriter struct {
Writer
}
func (wr *NoCloseWriter) Close() {
// do nothing
}

เวลาที่จะเรียก writeHelloAndClose เราก็แค่เอา NoCloseWriter มาครอบตัว MemoryWriter ของเรา

func main() {
wr := &MemoryWriter{}
writeHelloAndClose(&NoCloseWriter{wr})
wr.Write("other text")
fmt.Printf("wr: %s\n", wr.data)
}

ใน function writeHelloAndClose ก็จะเรียก Close จาก NoCloseWriter แทน ทำให้ตัว MemoryWriter ของเรายังไม่ถูกปิด


ไม่ยากเลยใช่ไหมครับ, จริง ๆ ในตัวอย่างนี้มี principle ตัวอื่น ๆ ซ่อนอยู่ด้วย ลองทายกันดูว่ามี principle ตัวไหนบ้าง xD

Like what you read? Give acoshift a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.