ใช้ static ได้ไหม

Static

วันหนึ่งระหว่างทำงานรุ่นน้องที่ทำงานถามว่าผมจะทำ Class แล้วใช้ Method เป็น Static ได้ไหม (static คือ keyword ของ java ที่ทำให้สามารถใช้ method หรือ attribute ได้โดยไม่ต้องสร้าง object) ตอนนั้นในสมองก็ผุดคำนึงตอนเรียนวิชา OOAD (Object-oriented analysis and design) ที่ว่า static is evil ขึ้นมาทันที แต่ตอนนั้นก็ต้องฟังก่อนว่าทำไมต้องใช้ จริงๆถามว่าใช้ได้ไหมคำตอบก็คือว่าได้ จริงๆแล้วจะทำอะไรก็ได้หมดแหละจะ SELECT * FROM TABLE แบบไม่ limit จะตั้งชื่อตัวแปรมั่วๆ หรืออะไรก็ตามแต่ แต่คำถามคือมันสมควรทำไหม ในมุมมองของผมการจะใช้ static ต้องดูงานที่จะใช้กับมันว่าทำไมต้องใช้ อย่างแรกเราต้องทำการแยกระหว่าง Class กับ Object ก่อน

Class Vs Object

ภาพแสดงความแตกต่างระหว่าง Class กับ Object ขอขอบคุณภาพจาก https://www.pinterest.com

ถ้าจะเปรียบเทียบ Class เปรียบเสมือนพิมพ์เขียวหรือกรอบที่บอกว่าสิ่งๆหนึ่งต้องมีค่าอะไรบ้างและสามารถทำอะไรได้บ้างเหมือนกับรูปภาพด้านบน Class Dog เป็นตัวบอกว่าหมาตัวนี้ต้องมีค่า Color, Height, Weight และต้องสามารถ Sit, LayDown ได้เป็นต้น แต่ Class ก็ยังคงเป็น Class เป็นแค่กรอบไม่ได้มีตัวตนจริงๆ การที่จะมี Dog จริงๆปรากฏขึ้นมาเราจะต้องทำการสร้าง Object ขึ้นมาภาษาโปรแกรมคือการ Create instance ขึ้นมา Object ที่ถูกสร้างขึ้นมาจะมีค่าเหมือนกับภาพด้านบนที่เมื่อเรา Create instance ของ Class Dog ออกมาเป็น Rayne (อ่านว่าอะไรไม่รู้) จะเห็นว่า Rayne จะมีค่า Attribute ต่างๆขึ้นมาจริงๆและสามารถเรียกใช้ Method ได้

มีไว้ทำไม Static

คราวนี้คำถามว่าแล้วจะมี Static ไปทำไมล่ะ บางครั้งเรามีบางสิ่งที่ไม่จำเป็นต้องมีตัวตนจริงๆแต่ก็สามารถใช้ได้ยกตัวอย่างง่ายๆของ Java คือ Class Math (ได้ยินชื่อแล้วนึกถึงตอนอ่าน Engineering mathematics 1 เลย) ที่มี method และ attribute ที่เกี่ยวกับการคำนวนไว้อยู่แล้วจะเห็นว่า Math ไม่จำเป็นต้องมีตัวตนจริงๆ (ในความหมายของผมคือ Object ) ก็ได้ (ถ้ามีตัวตนเลขวิ่งเข้ามาผมผมคงกลัวน่าดู)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// STATIC MAX_LEG

public class Dog {
public static final int MAX_LEG = 4;
....
}

// NORMAL MAX LEG

public class Dog2 {
public int MAX_LEG = 4;
.....
}

/// ANOTHER CLASS USE Dog and Dog2

// STATIC
System.out.println("Dog has max leg : " + Dog.MAX_LEG);

// NORMAL
Dog2 tempDog2 = new Dog2();
System.out.println("Dog has max leg : " + tempDog2.MAX_LEG);

หรือว่าบางที Class อาจจะมีคุณลักษณะบังคับที่ทุก Object ที่ถูกสร้างจาก class นั้นต้องมี และ เราต้องการบอกให้คนที่อ่าน class รู้ว่ามี ตัวอย่างเช่นค่าคงที่บางค่าเช่น เรากำหนดค่า MAX_LEG ของ Dog ให้เท่ากับ 4 เพื่อบอกให้ทั้งจักรวาลรู้ว่า Class Dog อะขามีมากสุดได้ 4 โดยเรียกใช้ผ่าน Class โดยใช้วิธี static แต่วิธีธรรมดาต้องสร้าง Object ขึ้นมาเพื่อถามว่า MAX_LEG มีเท่าไหร่ ลองนึกภาพตลกๆดูเอาละกันว่า อยากจะรู้ว่า Dog มีลักษณะคร่าวๆเป็นยังไงแล้วเราต้องสร้าง Object Dog ขึ้นมา 1 ตัว จากนั้นดูค่าขามากที่สุด พอหมดประโยชน์ก็ทำลาย Dog ทิ้งคงน่าสงสารแย่ (จริงๆคือมันเสียเวลาสร้างและ memory อีกต่างหาก)

ใช้ Static ทุกที่ไปเลย เย้

ตอนผมรู้จัก static ผมก็กะทำอย่างนี้เลยปัญหาคืองานบางงานมันไม่ได้ออกแบบมาให้ใช้ static ลองนึกภาพงานงานนึงนะครับต้องการ print ชื่อคนออกหน้าจอนะครับ ถ้าเขียนแบบ Static จะเป็นแบบนี้

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class People {
public String name;
}

public class PrintPeople {
public static void printPeople(People people) {
System.out.println("People name is : " + people.name);
}
}

// Use it
Perople people = new People();
people.name = "Syntax";

PrintPeople.printPeople(people);

จากภาพจะเห็นว่าแค่จะ Print ถึงกับต้องสร้าง 2 Class มาทำงานแบบนี้ ถามว่าจริงๆผิดไหม ผมว่าไม่ผิดหรอกครับคล้ายๆเราเขียนภาษา C ที่กำหนด struct แล้วเขียน function รับ struct เข้าไปเพื่อ print ออกมา แต่ตอนนี้เราเขียน OOP ที่มันมี method ผูกติดกับ Class แทนที่เราจะมี 2 class เราทำ class เดียวไปเลยสิ

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public class People {
public String name;
public void printPeople() {
System.out.println("People name is : " + name)
}
}

// Use it

Perople people = new People();
people.name = "Syntax";

people.printPeople();

อีกทั้งทุกครั้งที่เราประกาศ static method แล้วเรียกใช้ attribute หรือ method ใน Class ตัวเอง มันจะเป็นการบังคับให้เราต้องให้ attribute หรือ method ที่ถูกเรียกใช้เป็น static ไปด้วย (เหมือนไวรัส) และ ตัว Attribute ที่เป็น public static ที่ไม่ได้ประกาศ final มันก็คือ Global variable ดีๆนี่เอง ใครจะเรียกใช้ ใครจะแก้ก็ได้ตามใจ แก้ตอนไหนก็ไม่รู้ ดังนั้นอันตรายมากที่จะใช้ attribute เป็น public static

สรุป

หลังจากร่ายยาวมานานผมสรุปคร่าวๆได้ประมาณนี้ “เราสามารถใช้ทั้ง static และ ธรรมดาร่วมกันได้แล้วแต่สถาการณ์และความเหมาะสม” และจากนี้จะเป็นวิธีการเลือกใช้ไม่ใช้ static ตอนเขียน code ของตัวผมเองว่าตอนใช้ตอนไหนไม่ใช้

  • static
    1. เราใช้ static กับ Attribute มันเป็นค่าคงหรือค่าที่อยากให้ Class อื่นเห็นและสามารถใช้งานได้ ส่วนใหญ่ผมจะประกาศเป็น public static final type ATTRIBUTE_NAME = X ;
    2. เราใช้ static กับ Method เมื่อมันเป็นการใช้งานระดับ Class ไม่ใช่ระดับ Object ขอให้นึกถึงตอนเรียกใช้ Math หรือ MAX_LEG เป็นต้น
    3. เราใช้ static กับ Method เมื่อเรามองว่าเราสร้าง Class นั้นมาเป็น Util หรือ Function Class ประมาณว่าเป็น Class คอยช่วยทำงานบางอย่างซ้ำๆแบบไม่ต้องมีตัวตน Object ตัวอย่างที่เห็นได้ชัดคือ FileUtils, IOUtils

"สิ่งที่ผมเขียนขึ้นเป็นเพียงความรู้และความเข้าใจของบุคคลเพียงบุคคลเดียว ดังนั้นอย่าเพิ่งเชื่อในสิ่งที่ผมเขียนและอธิบาย ลองทำความเข้าใจว่ามันเป็นจริงอย่างนั้นไหมและลองหาแหล่งอ้างอิงอื่นๆว่าเขามีแนวคิดอย่างไร เรื่องการ Design และวิธีการใช้งานไม่มีถูกไม่มีผิดมีแต่เหมาะสมกับงานนั้นไหม"