สำหรับปัญหา Semantic FBC เป็นปัญหาที่มีผลกระทบมากกว่า Syntactic ครับ เพราะเป็นปัญหาระดับการออกแบบ ไม่ใช่ปัญหาระดับภาษาโปรแกรม นั่นหมายความว่าไม่ว่าเราจะเขียนโปรแกรมด้วยภาษา object-oriented ใด ๆ ถ้ามีการใช้ inheritance และ polymorphism มีโอกาสมีปัญหาได้หมด
ขอทบทวนอีกสักรอบนะครับว่าปัญหานี้คือปัญหาที่เมื่อมีการแก้ไขตรรกะการทำงานของโปรแกรมในคลาสแม่แล้ว มีผลทำให้พฤติกรรมของคลาสลูกเปลี่ยนไป โดยที่ไม่ได้มีการแก้ไขคลาสลูกเลย ซึ่งปัญหานี้ถ้าเกิดขึ้น จะสร้างความปวดหัวให้กับนักพัฒนาโปรแกรมมากครับ
เพื่อให้เข้าใจปัญหานี้มาเริ่มดูโค้ดภาษา Java ต่อไปนี้กันครับ ถ้าใครไม่อยากพิมพ์โค้ดเองดาวน์โหลดได้จากที่นี่เลยครับ
public class SemanticFBCSuperclass {
private int number;
public SemanticFBCSuperclass(int val) {
number = val;
}
public void f1() {
System.out.println("In f1() of SemanticFBCSuperClass");
//number++;
setNumber(number+1);
}
public void setNumber(int val) {
number = val;
}
}
คลาสนี้เป็นคลาสแม่นะครับ ให้สังเกตเมท็อด f1() นะครับมีการพิมพ์ข้อความหนึ่งบรรทัด และเพิ่มค่า number ซึ่งเป็น attribute ในคลาสนี้ขึ้น 1โดยใช้เมท็อด setNumber()
ต่อไปไปดูคลาสลูกของคลาสแม่ตัวนี้กันครับ
public class SemanticFBCSubclass extends SemanticFBCSuperclass {
public SemanticFBCSubclass(int val) {
super(val);
}
@Override
public void setNumber(int val) {
System.out.println("setNumber() overridden version");
super.setNumber(val);
}
}
จะเห็นว่าในคลาสลูกนี้ โอเวอร์รายด์ (override) เมท็อด setNumber() ของคลาสแม่ โดยพิมพ์ข้อความหนึ่งบรรทัด ก่อนที่จะเรียกเมท็อด setNumber() ของคลาสแม่
คราวนี้มาดู Main โปรแกรมกันครับ
*
* @author sarun
*/
public class FBC {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
SemanticFBCSubclass obj = new SemanticFBCSubclass(5);
obj.f1();
}
}
ที่ Main โปรแกรมก็ทำงานง่าย ๆ ครับ คือสร้างอ็อบเจกต์ของคลาสลูก แล้วเรียกเมท็อด f1() ซึ่งก็จะไปเรียกเมท็อด f1() ของคลาสแม่นะครับ เพราะคลาสลูกไม่มี f1() แค่คลาสลูกสืบทอดทุกสิ่งทุกอย่างจากแม่ เมื่อคอมไพล์และรันโปรแกรมจะได้ผลดังนี้ครับ
sarunintakosum@Saruns-MacBook-Pro semanticfbc % javac *.java
sarunintakosum@Saruns-MacBook-Pro semanticfbc % java FBC
In f1() of SemanticFBCSuperClass
setNumber() overridden version
sarunintakosum@Saruns-MacBook-Pro semanticfbc %
มาดูที่ผลัพธ์กันครับ ผลลัพธ์สองบรรทัดมาจากเมื่อเรียกเมท็อด f1() ก็จะเริ่มต้นทำงานโดยพิมพ์คำว่า
In f1() of SemanticFBCSuperClass
จากนั้นเรียกเมท็อด setNumber() แต่เนื่องจากอ็อบเจกต์ที่เรียกใช้เป็นอ็อบเจกต์ของคลาสลูก และเมท็อด setNumber() ถูกโอเวอร์รายด์ ดังนั้นจะเรียก setNumber() ของคลาสลูก ซึ่งก็จะพิมพ์คำว่า
setNumber() overridden version
จากนั้นจะกลับไปเรียก setNumber() ของคลาสแม่ต่อไป ถ้าตอนนี้ยังไม่เข้าใจก็เอาเป็นแค่ว่ามีผลลัพธ์สองบรรทัดนะครับ
คราวนี้สมมติว่ามีการทบทวนคลาสแม่กันใหม่ แล้วก็เห็นว่าใน f1() ถ้าจะเพิ่มค่า number ขึ้น 1 จะทำงานเร็วขึ้น ถ้าเพิ่มค่าตรง ๆ เลย ไม่ต้องไปเรียกเมท็อด setNumber() ดังนั้นคลาสแม่จึงถูกแก้เป็นดังนี้ครับ
public class SemanticFBCSuperclass {
private int number;
public SemanticFBCSuperclass(int val) {
number = val;
}
public void f1() {
System.out.println("In f1() of SemanticFBCSuperClass");
number++;
//setNumber(number+1);
}
public void setNumber(int val) {
number = val;
}
}
จะเห็นนะครับว่าใน f1() ไม่เรียก setNumber() แล้ว
จากนั้นคอมไพล์คลาสแม่และรันโปรแกรมครับ
sarunintakosum@Saruns-MacBook-Pro semanticfbc % javac SemanticFBCSuperclass.java
sarunintakosum@Saruns-MacBook-Pro semanticfbc % java FBC
In f1() of SemanticFBCSuperClass
sarunintakosum@Saruns-MacBook-Pro semanticfbc %
จะเห็นนะครับว่าผลลัพธ์เหลือ 1 บรรทัดแล้วนะครับ เพราะเมื่อไม่ได้เรียก setNumber() ก็จะไม่ไปเรียก setNumber() ของคลาสลูก ผลลัพธ์เปลี่ยนโดยที่เราไม่ได้แตะโค้ดของคลาสลูกเลย สมมติถ้าคลาสแม่เราไม่ได้เขียนเอง พอมีการเปลี่ยนเวอร์ชันของคลาสแม่แล้วส่งมาให้เราใช้ ปรากฏว่าโปรแกรมให้ผลลัพธ์เปลี่ยนไปจากเดิม ลองคิดดูครับว่าถ้านี่เป็นระบบงานที่เราทำจริง ๆ ที่มีความซับซ้อน มันจะยุ่งแค่ไหน และถ้าเราไม่มีโค้ดของคลาสแม่ เราก็อาจไม่รู้เลยว่าเกิดอะไรขึ้น และปัญหานี้แก้ไม่ได้ด้วยการคอมไพล์ใหม่ วิธีแก้คือต้องออกแบบกันใหม่อย่างเดียว
ดังนั้นคงเห็นแล้วนะครับว่าปัญหา FBC โดยเฉพาะ Semantic FBC ทำให้เกิดปัญหาถ้าต้องมีการเปลี่ยนแปลงโปรแกรม เนื่องจากมีความขึ้นต่อกันระหว่างคลาสแม่และคลาสลูก ดังนั้นในการพัฒนาโปรแกรมโดยใช้แนวคิดของคอมโพเนนต์ จึงหลีกเลี่ยงการใช้งาน inheritance และ polymorphism และใช้การประกอบแทน
ก็เป็นอันว่าจบชุดของปัญหา FBC กันไว้ตรงนี้นะครับ โอกาสหน้าจะเขียนเรื่องอะไร ถ้าสนใจก็คอยคิดตามได้นะครับ
ไม่มีความคิดเห็น:
แสดงความคิดเห็น