Polymorphisms
Polymorphisms สรุปง่ายๆว่าเป็นการอนุญาติให้ derived class ( child class ) สามารถใช้ function ของ parent ได้ สำหรับ polymorphisms นั้นเห็นเด่นชัดมากที่สุดก็คงจะเป็น Overriding / Overloading

Overriding
เป็นการเขียน function ของ Child class ใช้เองโดยไม่ต้องใช้ function ของ Parent Class ถ้าจะยกตัวอย่างง่ายๆ ก็เป็นต้นว่า ถ้าเรามี class ชื่อว่า Car แล้ว Car นั้นมีฟังชั่นขื่อว่า drive สมมติว่าเราจะเขียน class ใหม่ขึ้นมาโดยสืบทอด (inherit) มาจาก Car โดยชื่อว่า Tank มีฟังชั่นชื่อว่า drive เหมือนกัน แต่ว่า class ทั้งสองนั้น Drive ทำงานไม่เหมือนกัน คือพูดง่ายๆว่า รถยนต์ก็ ขับ(drive)ได้ รถถังก็ ขับ(drive) ได้ แต่วิธีการที่จะขับไม่เหมือนกัน
Overloading
เป็นการเขียน Function ชื่อเหมือนกัน ใน class เดียวกัน แต่รับ parameter คนละอย่างกัน เช่นว่า เรามี class ชื่อว่า Rectangle และมี function ในการคำนวนพื้นที่ เราอาจจะต้องการให้มันรับ parameter ได้ทั้ง int และ float ในลักษณะแบบนี้เราก็จะใช้ overloading เข้ามาให้เกิดประโยชน์
อาจจะงง เล็กน้อย สรุปสั้น Overriding ก็คือ child class ที่มีการเขียน function ที่ชื่อเหมือนกับ parent ขึ้นมาเองโดยไม่ต้องสืบทอดจาก parent และ Overloading คือ method ที่สามารถรับ parameter ได้หลายๆรูปแบบ

แต่มาดู code อาจจะเข้าใจง่ายกว่า




// Car.h
#import
@interface Car:Object {
int m_speed;
}
- (void) drive;
- (void) drive:(int)speed;
@end


และในส่วน implement




// Car.m
#import
@implementation Car;
- (void) drive
{
printf("Car drive n");
}
- (void) drive:(int)speed
{
m_speed = speed;
printf ("Car drive at speed %d n",m_speed); }
@end


จากตัวอย่างข้างบนเป็นการ แสดงให้เห็นถึง Overloading คือ จะเห็นว่า Car นั้นมี Function ชื่อเหมือนกัน นั่นคือ drive แต่รับ parameter มาไม่เหมือนกัน โดยที่ drive แรกนั้น ไม่ได้รับ parameter มาเลย ส่วนตัวที่สอง รับ int เข้ามาและ ก็ในส่วนการทำงานของแต่ละฟังชั่นก็ต่างกัน

เวลาเรียกใช้เราอาจจะเขียนได้ว่า



#import "car.h"
int main()
{
Car *honda = [[Car alloc] init];
[honda drive];
[honda drive:80];
return 0;
}

ส่วนผลลัพธ์ที่ออกมาก็จะเป็น

Car drive
Car drive at speed 80

ทีนี้เรามาดู Overriding กันบ้าง ก็อย่างที่บอกไปแล้วว่า เราสารมารถเขียน ให้ child class ทำงานต่างจาก parent โดยที่ ขื่อเหมือนกันได้มาดู กันเลยดีกว่า



// Tank.h
#import "car.h"
@interface Tank:Car {
}
@end

ก็จะเห็นว่าใน class tank นั้นไม่มีอะไรเลย คือ inherit มาจาก car อย่างเดียว
แต่เราสารมารถเขียน implement ของตัวเองโดยอิงจาก parent ได้



#import "tank.h"
@implementation Tank
- (void) drive
{
printf ("Tank Driven");
}
@end

ก็เป็นอันเสร็จ คือเรา เขียน funtion drive ขึ้นมาใหม่ แทนที่ ตัวเก่าที่มีอยู่ใน Car

และก็มาลองเรียกใช้งานกันดู



#import "car.h"
#import "tank.h
int main()
{
Car *honda = [[Car alloc] init];
Tank *tank = [[Tank alloc] init];
[honda drive];
[tank drive];
[tank drive:20];
return 0;
}

ส่วนผลลัพธ์ที่ได้ก็จะได้ว่า
Car drive

Tank drive
Car drive at speed 20

จากผลลัพธ์ก็จะเห็นว่า Tank drive ที่ออกมา โปรแกรมจะไปเรียก function ใน class Tank

ส่วนบรรทัดสุดท้าย ตัวโปรแกรมจะไปเรียกใช้ parent ของ tank นั่นก็คือ Car เพราะเนื่องจากว่า tank นั้น Overriding เพียงแค่ฟังชั่น



- (void) drive;


แต่สำหรับ


- (void) drive:(int)speed;

ไม่ได้ทำการ overriding

มันจึงไปใช้งาน parent ของมันแทน

Dynamic Binding

คือไม่รู้ว่าจะอธิบายง่ายๆได้อย่างไรว่ามันคืออะไร แต่เอาเป็นว่า ขอยกตัวอย่าง Dynamic Binding ให้เห็นภาพได้ว่า สมมติว่า เรามี class ชื่อว่า Dog และ Cat โดนทั้งสอง class นี้เป็น child ของ Animal และมี function ชื่อว่า eat เหมือนกัน ดู code ตัวอย่างภาษา C ต่อไปนี้



void function_eat(Animal *a)
{
a->eat();
}


ถ้าสมมติว่า เราเรียก funciton_eat โดยส่ง pointer ของ Cat และ dog มาให้ในลักษณะแบบนี้


Cat *c = new Cat();
Dog *d = new Dog();
function_eat(c);
function_eat(d);


ะเห็นว่า เราสามารถส่ง ทั้ง Cat และ Dog ไปให้ function_eat ได้ เพราะว่าทั้ง Cat
และ Dog นั้นเป็น Animal ทั้งคู่ ปัญหาก็คือว่าโปรแกรมจะรู้ได้ยังไงว่าควรจะไปเรียก
eat ของ cat หรือว่าไปเรียก eat ของ dog
ตรงนี้ไม่ต้องกังวลเพราะว่าโปรแกรมจะไปตรวจสอบเองว่า Animal ที่ได้รับมาเป็น dog
หรือ cat กระบวนการที่โปรแกรมสามารถจำแนกได้ว่าเป็น class ใดนั้นเหละคือ Dynamic Binding

id Type

ในภาษา objective-c นั้นจะมีตัวแปรชนิดพิเศษที่ชื่อว่า id ตัวแปรชนิดนี้มันจะคล้ายๆลักษณะ pointer ในภาษา C แต่ id มันสามารถ เก็บค่าอะไรก็ได้ !!!

มาดูตัวอย่างอาจจะพอเห็นภาพมากกว่า



#import 
#import

//---------- Human ------------
//------ Human Interface---------
@interface Human:Object
{
}
- (void) printHuman;
@end
//------ Human Implement ------
@implementation Human;
- (void) printHuman
{
printf("Human \n");
}
@end


//---------- Animal ------------
//------ Animal Interface---------
@interface Animal:Object
{
}
- (void) printAnimal;
@end
//------ Animal Implement------
@implementation Animal;
- (void) printAnimal
{
printf("Animal \n");
}
@end


//------ MAIN ---------
int main()
{
id both;
Human *h = [[Human alloc] init];
Animal *a = [[Animal alloc] init];
both = h;
[both printHuman];
both = a;
[both printAnimal];
return 0;
}

คือจาก code ข้างบน ประกาศ class ไว้คือ Human กับ Animal และทั้งสอง class นี้ก็ไม่ได้เกี่ยวกันแต่อย่างได
มาดูที่ main โปรแกรมจะเห็นว่า ประกาศ ตัวแปรมา 3 ตัวก็คือ both , h , a ซึ่งทั้งสามตัวแปรนี้เป็นคนละชนิดกัน จุดที่อยากให้รู้ก็คือว่า เราประกาศ both เป็น id สามารถเก็บอะไรก็ได้ และ

  • เราก็ลองมาให้ both มีค่าเท่ากับ h หลังจากนั้นก็ลองเรียก printHuman
  • เสร็จแล้ว ก็ให้ both มีค่าเท่ากับ a แล้วก็เรียก printAnimal

จะเห็นว่ามันสามารถสลับเปลี่ยนไปเป็น Human หรือ Animal และเรียก function ของทั้งสองได้ ผลลัพธ์ที่ได้ก็จะเป็นแบบนี้

Human
Animal

และการใช้งานลักษณะแบบนี้ก็เป็น dynamic binding นั่นเอง ก็อาจจะเกิดคำถามที่ว่า ก็ในเมื่อมันเก็บได้ทุกอย่าง เราก็ประกาศให้มันเป็น id หมดเลยก็ได้ คำตอบก็คือได้ แต่ไม่ควรทำ ด้วยหลายๆเหตุผล ขอยกตัวอย่างง่ายๆว่า

id a;

กับ

Animal a;

สองอย่างนี้ อะไรเข้าใจง่ายกว่า ว่า a คืออะไร?
ระหว่างบอกว่า a เป็น animal กับ a เป็น id ?
จริงๆมันก็มีอีกหลายๆเหตุผลที่ว่า เราควรใช้ในสิ่งที่จำเป็นมากกว่า ขอยกตัวอย่าง อีกสักอัน

สมมติว่าจาก code ตัวอย่างแรก เรามาแก้ให้เป็นแบบนี้




boht = human;
[both printAnimal];

จะเห็นว่า เราให้ both นั้นเป็น human แต่เรากลับไปเรียกใช้ printAnimal
ซึ่งไม่มีใน Human แน่นอน … แต่เวลา Compile นั้นโปรแกรมจะไม่สามารถตรวจสอบได้ว่า
มันไม่มี printAnimal โปรแกรมจะสามารถ Compile ได้ปกติโดยไม่เกิด
error เพราะว่า dynamic binding นั้นจะเกิดขึ้นตอนโปรแกรมเริ่มทำงาน
ดังนั้นถ้าเราเรียกใช้โปรแกรมดังกล่าว ก็จะเกิด error
ทันที

และจะได้ผลลัพธ์ในลักษณะแบบนี้

Human
error: Animal (Instance)
Animal does not recognize printHuman


ฉนั้นการใช้ก็ควรจะระวังกันสักนิด

0 ความคิดเห็น:

แสดงความคิดเห็น