470 likes | 640 Views
Polymorphism and Interface. อ. นัฐพงศ์ ส่งเนียม http://www.siam2dev.com xnattapong@hotmail.com. โพลีมอร์ฟิซึม (Polymorphism). ความหมาย โพลีมอร์ฟิซึม หมายถึง แนวความคิดในการติดต่อด้วยวิธีเดียวกันกับหลายๆ สิ่ง ส่วนผลที่จะได้รับอาจแตกต่างกัน เป้าหมาย
E N D
Polymorphism and Interface อ. นัฐพงศ์ ส่งเนียม http://www.siam2dev.com xnattapong@hotmail.com http://www.siam2dev.com
โพลีมอร์ฟิซึม (Polymorphism) • ความหมาย • โพลีมอร์ฟิซึม หมายถึง แนวความคิดในการติดต่อด้วยวิธีเดียวกันกับหลายๆ สิ่ง ส่วนผลที่จะได้รับอาจแตกต่างกัน • เป้าหมาย • ลดภาระในการจำคำสั่ง คำสั่งเดียวติดต่อได้ทุกที่ (many form) • ลดภาระในการแก้ไขคำสั่งภายในเมธอด สามารถเพิ่มหรือแก้ไขรายละเอียดภายในเมธอดชื่อเดิมได้ (override) โดยไม่กระทบกระเทือนของเดิม http://www.siam2dev.com
ตัวอย่างโพลีมอร์ฟิซึมตัวอย่างโพลีมอร์ฟิซึม • ระบบพนักงาน (Employee System) • ในบริษัทแห่งหนึ่งมีพนักงาน 2 ประเภท คือ พนักงานรายเดือน (Salaried Employee) พนักงานรายชั่วโมง (Hourly Employee) ในแต่ละเดือนบริษัทต้องคำนวณการจ่ายเงินให้พนักงาน วิธีคิดแตกต่างกัน แต่อย่างไรก็ตามพนักงานทั้งสองประเภทก็มีลักษณะร่วมกัน ได้แก่ หมายเลขประจำตัว ชื่อ แผนก • ในอนาคตอาจมีพนักงานจ้างตามชิ้นงาน (Piece Employee) เพิ่มมา ? • ต้องการสร้างเมธอด pay() ชื่อเดียว แต่สามารถใช้ได้กับพนักงานทุกประเภท อันนี้ถือว่าเป็นการนำเอาความสามารถด้านโพลีมอร์ฟิซึมมาใช้ http://www.siam2dev.com
ตัวอย่างโพลีมอร์ฟิซึมตัวอย่างโพลีมอร์ฟิซึม Employee SalariedEmployee HourlyEmployee http://www.siam2dev.com
ตัวอย่างโพลีมอร์ฟิซึมตัวอย่างโพลีมอร์ฟิซึม Employee.java public class Employee { protected String firstName; protected String lastName; protected String pid; // personal id public Employee() { firstName =""; lastName=""; pid="";} public Employee(String newFirstName, String newLastName, String newPid) { firstName = newFirstName; lastName = newLastName; pid = newPid; } //end Continue http://www.siam2dev.com
Employee.java public void setName(String newFirstName, String newLastName){ firstName = newFirstName; lastName = newLastName; } public void setPid(String newPid){ pid = newPid; } public String getName(){ return firstName + " " + lastName; } public String getPid(){ return pid; } public double pay(){ return 0;} public String toString(){ return "PID:" + pid + " Name:" + getName(); } }//end Employee http://www.siam2dev.com
SalariedEmployee.java public class SalariedEmployee extends Employee { protected double salary; public SalariedEmployee() { } public SalariedEmployee(String fName, String lName, String newPid,double newSalary) { super(fName,lName,newPid); salary = newSalary; } //end public void setSalary(double newSalary){ salary = newSalary; } public double pay(){ return salary;} public String toString(){ return super.toString() + " Salary : " + salary; } }//end SalariedEmployee http://www.siam2dev.com
HourlyEmployee.java public class HourlyEmployee extends Employee { protected double hour; protected double rate; public HourlyEmployee() { hour =0;} public HourlyEmployee(String fName, String lName, String newPid, double h,double r) { super(fName,lName,newPid); hour = h; rate = r; } //end public void setHour(double newHour){ hour = newHour; } public void setRate(double newRate){ rate = newRate; } public double pay(){ return hour * rate;} public String toString() { return super.toString() + "\n\t\t Hour: " + hour + " Rate: " + rate + " Total: " + this.pay(); } }//end HourlyEmployee http://www.siam2dev.com
EmployeeTest.java public class EmployeeTest { public static void main(String[] args) { System.out.println("Polymorphism Testing!"); Employee e= new Employee("Chery","Meesuk","36001"); System.out.println("Employee: " + e.toString()); SalariedEmployee s= new SalariedEmployee("Vipa","Thongdee", "36002",25000); System.out.println("Salaried Employee: " + s.toString()); HourlyEmployee h= new HourlyEmployee("Anun","Kam", "346003",30, 150); System.out.println("Hourly Employee:" + h.toString()); System.out.println("\nThe reference of Parent class can refer to an instance of its subclass"); Employee emp[] = new Employee[2]; emp[0] = s; emp[1] = h; System.out.println(emp[0].pay()); System.out.println(emp[1].pay()); } //end main method } } //end EmployeeTest http://www.siam2dev.com
คุณสมบัติของโพลีมอร์ฟิซึมในการเขียนโปรแกรมคุณสมบัติของโพลีมอร์ฟิซึมในการเขียนโปรแกรม • การอ้างอิง • ตัวอ้างอิงของคลาสแม่สามารถอ้างถึงอ็อบเจกต์ที่สร้างจากคลาสลูกได้ • ตัวอ้างอิงของคลาสลูกไม่สามารถอ้างถึงอ็อบเจกต์ที่สร้างจากคลาสแม่ได้ Employee e; SalariedEmployee s= new SalariedEmployee("Vipa","Thongdee", "36002",25000); e =s;// ok Employee ep = new Employee(“Anong”,”Ratmanee”,”3444”); SalairedEmployee t; T = ep ; //not ok http://www.siam2dev.com
คุณสมบัติของโพลีมอร์ฟิซึมในการเขียนโปรแกรมคุณสมบัติของโพลีมอร์ฟิซึมในการเขียนโปรแกรม Employee emp[] = new Employee[2]; emp[0] = s; emp[1] = h; System.out.println(emp[0].pay()); System.out.println(emp[1].pay()); Employee e1 = s; Employee e2 = h; Employee e3 =new SalariedEmployee("Siri","Pongdee", "36006",35000); System.out.println(e3.toString()); Employee e4 = new HourlyEmployee("Suchart","Kamkaew", "346007",20, 2500); System.out.println(e4.toString()); http://www.siam2dev.com
คลาสนามธรรม (Abstract Classes) • คลาสนามธรรม หมายถึง • คลาสต้นแบบเท่านั้น ไม่สามารถนำไปใช้สร้าง object ของตัวเองได้ • มีเมธอดนามธรรม (abstract methods) เพื่อบังคับให้คลาสลูกที่สืบทอดไปต้องนำเอาเมธอดนั้นไปดัดแปลงก่อนใช้เสมอ • ตัวอย่าง • คลาส Employee สามารถกำหนดให้มีคุณสมบัติข้างต้นได้ คือ เมธอด pay() กับ toString() ได้รับการดัดแปลง(overridden) http://www.siam2dev.com
การสร้างคลาสนามธรรมใน Java public CircleDrawing extends ShapeDrawing { public void draw(Graphics g) { g.drawOval(point.getX(),point.getY(),wPicxel, hPicxel); } } //end class public abstract ShapeDrawing { protected Point point; //origin protected int wPicxel; // width protected int hPicxel; // height public abstract void draw(Graphics g); } //end class สร้าง Object ไม่ได้ ไม่ต้องมีรายละเอียด สืบทอดจากคลาสนามธรรม ดัดแปลงใหม่ http://www.siam2dev.com
import java.awt.*; public abstract class ShapeDrawing { protected int x; protected int y; protected int wPicxel; protected int hPicxel; public ShapeDrawing() { ; } public ShapeDrawing(int newX, int newY){ x= newX; y = newY; wPicxel = 50; hPicxel = 50; } public ShapeDrawing(int newX, int newY, int w, int h){ x=newX; y = newY; wPicxel = w; hPicxel = h; } public void setXY(int xx,int yy) { x=xx; y = yy;} public void setWidthPicxel(int w) { wPicxel = w;} public void setHeightPicxel(int h) { hPicxel = h;} public void move(int xx,int yy){ setXY(xx,yy);} public abstract void draw(Graphics g); } //end class ShapeDrawing.java http://www.siam2dev.com
import java.awt.*; public class CircleDrawing extends ShapeDrawing { public CircleDrawing(){ } public CircleDrawing(int newX,int newY,int w,int h){ super(newX,newY,w,h); } public void draw(Graphics g){ g.drawOval(x,y,wPicxel,hPicxel); } } //end class CircleDrawing.java import java.awt.*; public class RectangleDrawingextends ShapeDrawing { public RectangleDrawing(){ } public RectangleDrawing(int newX,int newY,int w, int h){ super(newX,newY,w,h); } public void draw(Graphics g){ g.drawRect(x,y,wPicxel,hPicxel); } } //end class RectangleDrawing.java http://www.siam2dev.com
import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.awt.Point; public class ShapeTest extends JApplet implements MouseListener { CircleDrawing myCircle; RectangleDrawing myRect; Object obj[]; ShapeDrawing sh[]; java.awt.Point cPoint; String text; public static void main(String[] args) { System.out.println("Application"); } public void init() { myCircle = new CircleDrawing(10,20,40,40); myRect = new RectangleDrawing(100,20,50,50); obj = new Object[2]; obj[0] = myCircle; obj[1] = myRect; cPoint = new Point(50,200); text = "draw"; addMouseListener(this); } ShapeTest.java http://www.siam2dev.com
ShapeTest.java public void paint(Graphics g) { super.paint(g); for(int i =0;i< obj.length; i++) ((ShapeDrawing)obj[i]).draw(g); g.drawString(text,(int)cPoint.getX(),(int)cPoint.getY()); } public void mousePressed(MouseEvent event) { cPoint= event.getPoint(); myCircle.move((int)cPoint.getX(),(int)cPoint.getY()); text = "Move"; repaint(); } public void mouseClicked(MouseEvent event) { } public void mouseReleased(MouseEvent event) { } public void mouseEntered(MouseEvent event) { } public void mouseExited(MouseEvent event) { } } Polymorphism http://www.siam2dev.com
สรุปการใช้ Polymorphism • สร้างคลาสแม่ที่บรรจุเมธอดทั้งหมดที่จำเป็นในการแก้ปัญหา • เมธอดใด ที่มีความเฉพาะตัวตามคลาสลูกที่สืบทอดไป ต้องประกาศเป็น abstractmethod • นิยามคลาสลูกที่สืบทอดมา และนำเอาเมธอดนามธรรมมาดัดแปลงใหม่ • สร้าง Object จากคลาสลูกต่างๆ และอ้างถึงอ็อบเจกต์เหล่านั้นโดยใช้ตัวอ้างอิงจากคลาสแม่ (super class references) http://www.siam2dev.com
การป้องกันดัดแปลงเมธอด และสืบทอดคลาส (final methods and classes) • การป้องกันการดัดแปลงเมธอดของคลาสแม่ในคลาสลูก • ใช้ final ประกาศหน้าเมธอดของคลาสแม่ แล้วคลาสลูกจะไม่สามารถดัดแปลงเมธอดนั้นได้อีก (not overridden) • เมธอดที่ประกาศเป็น static ถือว่าเป็น final โดยอัตโนมัติ Public class T { public T() { } public final void method1(){ System.out.println(“ Final method”); } } //end class http://www.siam2dev.com
การป้องกันดัดแปลงเมธอด และสืบทอดคลาส (final methods and classes) • การป้องการสืบทอดในคลาส • ถ้ามีการประกาศ final ในคลาสใดๆ แสดงว่าคลาสนั้นไม่สามารถนำไปสืบทอดเป็น super class ของคลาสอื่นได้ • ตัวอย่าง คลาส String ไม่สามารถนำไปสืบทอดสร้างคลาสย่อยใหม่ได้ http://www.siam2dev.com
THE TYPE-WRAPPER CLASSES FOR PRIMITIVE TYPES • คลาสตัวห่อหุ้มชนิดข้อมูล • ชนิดข้อมูลพื้นฐาน short, int ,long,char,float,double และ boolean ไม่ใช่ คลาส • คลาสเหล่านี้มีสิ่งร่วมกันหลายสิ่ง เช่น การแปลงสายอักขระ เป็นตัวเลข • เพื่อความสะดวกในการเขียนโปแกรมเชิงวัตถุ ต้องมีคลาสมาห่อหุ้มชนิดข้อมูลเหล่านี้เอาไว้ http://www.siam2dev.com
THE TYPE-WRAPPER CLASSES FOR PRIMITIVE TYPES Object Boolean Char Number Double Byte Integer Short Long Float http://www.siam2dev.com
THE TYPE-WRAPPER CLASSES FOR PRIMITIVE TYPES • คลาสตัวห่อหุ้มชนิดข้อมูล • เป็นคลาสแบบ final ไม่สามารถนำไปสืบทอดได้ • ส่วนใหญ่มีเมธอดที่ประกาศเป็น static เช่น paseInt ของ Integer int x ; X = Integer.paseInt(10); double d; d= Double.paseDouble(1345.45); float f; f = Float.paseFloat(134.50); http://www.siam2dev.com
การใช้ interfaces • Interface คืออะไร • การประกาศกลุ่มของเมธอดที่คลาสต่างๆ ใช้ชื่อร่วมกัน ส่วนรายละเอียดของเมธอดเหล่านั้น คลาสที่นำไปใช้ต้องเขียนเอง • การประกาศ Interface ไม่ใช่การสืบทอดโดยตรง เพราะแต่ละเมธอด อาจนำไปพัฒนารายละเอียดแตกต่างกันตามคลาสที่นำไปใช้ ไม่มีข้อมูลต้องใช้ร่วมกัน http://www.siam2dev.com
การใช้ interfaces • วิธีสร้าง Interfaces ใช้คำสงวน interface แทนคลาส ภายในบรรจุเมธอดโดยไม่ต้องระบุรายละเอียด • การนำไปใช้ • ใช้คำสงวน implements ตามด้วยชื่อ interface • เมธอดทุกตัวใน interface ต้องมีรายละเอียด { } http://www.siam2dev.com
การใช้ interfaces public interface Shape{ public double getArea(); public double getVolume(); public String getName(); } • วิธีสร้าง interface public class Circle extends Object implements Shape{ public double r; public double getArea(){ return Math.PI * r*r; } public double getVolume() { } public String getName() { return “circle”;} } http://www.siam2dev.com
ตัวอย่างการใช้ Interface เพื่อลดการเขียนคำสั่ง • ปัญหา สมมุติว่าเราต้องการเขียนโปรแกรมเรียงข้อมูล เมธอดเดียวสามารถรองรับการเรียงข้อมูลได้หลายประเภทสามารถทำได้ด้วยการใช้ interface http://www.siam2dev.com
ตัวอย่างการใช้ Interface เพื่อลดการเขียนคำสั่ง Relation.java public interface Relation { public boolean isGreater(Object b); public boolean isLess(Object b); public boolean isEqual(Object b); } http://www.siam2dev.com
Rectangle.java import java.text.DecimalFormat; public class Rectangle implements Relation { private double x; private double y; private double width; private double length; public Rectangle() { } public Rectangle(double x1,double y1, double w,double len) { x = x1; y=y1; width = w; length = len; } //end Constructor public double area(){ return width*length;} public boolean isGreater(Object b) { return area() > ((Rectangle)b).area(); } public boolean isLess(Object b){ return area() < ((Rectangle)b).area(); } public boolean isEqual(Object b) { return area() == ((Rectangle)b).area(); } Continue http://www.siam2dev.com
Rectangle.java public String toString(){ String s; DecimalFormat out = new DecimalFormat("0.00"); s = "Rectangle (" + out.format(x) + "," + out.format(y) + ") " + " \twidth = " + out.format(width) + " \tlength = " + out.format(length) + " \tarea =" + out.format(area()); return s; } }//end class http://www.siam2dev.com
Cubic.java import java.text.DecimalFormat; public class Cubic implements Relation { private double x; private double y; private double width ; private double length; private double height; public Cubic() { } public Cubic(double x1,double y1, double w,double len, double h) { x = x1; y=y1; width = w; length = len; height = h; } //end Constructor public double volume(){ return width*length*height;} public boolean isGreater(Object b) { return volume() > ((Cubic)b).volume(); } public boolean isLess(Object b){ return volume() < ((Cubic)b).volume(); } public boolean isEqual(Object b) { return volume() == ((Cubic)b).volume(); } Continue http://www.siam2dev.com
Cubic.java public String toString(){ String s; DecimalFormat out = new DecimalFormat("0.00"); s = "Cubic (" + x + "," + y + ") " + " \tWidth = " + out.format(width) + " Length=" + out.format(length) + " Height=" + out.format(height) + " \tVolume=" + out.format(volume()); return s; } }//end class http://www.siam2dev.com
คลาสเรียงข้อมูล SortObject.java public class SortObject { public static Object[] sort(Object[] data) { Object temp; for(int i = 0 ; i < data.length-1; i++) for(int j = 0; j< data.length-1-i; j ++) { if ( ( (Relation)data[j]).isGreater( (Relation)data[j+1] ) ) { temp = data[j]; data[j] = data[j+1]; data[j+1] = temp; } //end if } return data; } //end sort } //end class http://www.siam2dev.com
SortRectangleTest.java public class SortRectangleTest { public static void main(String[] args){ Object rect[] = new Rectangle[4]; //create objects rect[0] = new Rectangle(10,0,5,10); rect[1] = new Rectangle(10,20,10,15); rect[2] = new Rectangle(20,5,5,2); rect[3] = new Rectangle(100,20,6,5); SortObject.sort(rect); System.out.println("Sorted Rectangles by size"); for(int i = 0 ; i < rect.length-1; i++) { System.out.println(rect[i].toString() ); } //end for Object c[] = new Cubic[4]; Continue http://www.siam2dev.com
SortRectangleTest.java //create objects c[0] = new Cubic(10,0,5,5,5); c[1] = new Cubic(10,20,10,15,5); c[2] = new Cubic(20,20,5,2,5); c[3] = new Cubic(30,20,6,5,5); System.out.println("\nSorted Cubics by volume"); SortObject.sort(c); for(int i = 0 ; i < c.length-1; i++) { System.out.println(c[i].toString() ); } //end for } //end main method } //end class http://www.siam2dev.com
ผลลัพธ์ http://www.siam2dev.com
ประโยชน์ของ interface • การใช้ Interface • คลาสที่มีการประกาศ implements จากอินเตอร์เฟรส มีพฤติกรรมเกือบเหมือนคลาสย่อยที่สืบทอดจากคลาสนามธรรมที่มีชื่อ เมธอดนามธรรมเหมือนกัน • ทำไมไม่ใช้ คลาสนามธรรมแทน interface เลยทั้งหมดละ? • เหตุผล ใน Java ไม่อนุญาตให้สืบทอดหลายคลาสได้พร้อมกันเหมือนใน C++ • การใช้ interface สามารถนำมาแก้ปัญหานี้ได้ เพราะคลาสใด สามารถ implement ได้หลาย interface พร้อมกัน ทำให้สะดวก และยืดหยุ่นในการใช้งาน http://www.siam2dev.com
การออกแบบคลาสซ้อนคลาส (Nested Classes) • คลาซ้อนคลาส • เป็นคลาสที่สามารถประกาศในคลาสอื่นได้ ซึ่งเรียกคลาสนี้ว่า nested classes • Nested classes อาจเป็น static • Nested classes ที่ไม่เป็น static เรียกว่า inner classes • Inner classes ใช้มากในการเขียนโปรแกรมจัดการกับเหตุการณ์ http://www.siam2dev.com
LinkedList.java public class LinkedList { class Node { String text; Node next; Node() {text = ""; next=null;} Node(String s) { text = s; next = null;} }; private Node firstNode; LinkedList(){ firstNode = null; } public void add(String s) { Node newNode = new Node(s); Node lastNode=null, currentNode; if(firstNode == null) firstNode = newNode; else { currentNode = firstNode; while(currentNode != null) { lastNode = currentNode; currentNode = currentNode.next; } //end while if(lastNode != null) lastNode.next = newNode; } //end } //end add http://www.siam2dev.com
LinkedList.java public String remove(){ Node currentNode = firstNode; firstNode = currentNode.next; return currentNode.text; } public String getAllNode() { String s=""; Node currentNode = firstNode; while (currentNode !=null) { s = s + currentNode.text + "\n"; currentNode = currentNode.next; } return s; }//end getAllNode public boolean isempty(){ return firstNode==null;} } //end class http://www.siam2dev.com
การนำคลาส LinkedList มาใช้ LinkedListTest.java public class LinkedListTest { public static void main(String[] args) { LinkedList myList = new LinkedList(); myList.add("Ant"); myList.add("Bison"); myList.add("Cat"); myList.add("Dolphin"); String strOut = myList.getAllNode(); System.out.println(strOut); } } //end class http://www.siam2dev.com
ทดสอบตัวเองหลังเรียน • นักศึกษาควรตอบตัวเองว่าได้รู้สิ่งต่อไปนี้หรือยัง • What is inheritance? • What is polymorphism • What are abstract classes and abstract methods? Why would you wish to use an abstract classes and methods in your program? • What are the advantages of declaring methods or classes to be final? What are the disadvantages? • What is an interface? How do interfaces save programming effort? http://www.siam2dev.com
การบ้านส่งในชั่วโมงต่อไปการบ้านส่งในชั่วโมงต่อไป • 1. จงสร้างคลาส Polygon สืบทอดจากคลาส ShapeDrawing เพื่อเก็บอะเรย์ของอ็อบเจกต์ที่สร้างจากคลาส Point ซึ่งเก็บจุดโคออร์ดิเนต (x,y) แล้วเมื่อสั่งเมธอด draw() ของ Polygon แล้วให้วาดเส้นตรงเชื่อมระหว่างจุดทุกจุด การทดสอบคลาส Polygon ให้สร้าง applet เพื่อวาด http://www.siam2dev.com
การบ้านส่งในชั่วโมงต่อไปการบ้านส่งในชั่วโมงต่อไป 2. จงเขียนคลาส TestPolymorphism เป็น applet เพื่อให้สร้างอะเรย์ของคลาส Object เพื่อให้รองรับการวาดอ็อบเจกต์ที่เกิดจากคลาส Circle, Rectangle, และ Polygon แล้วสั่ง for(int i=0; i<obj.length;i++) ((ShapeDrawing)obj[i]).draw(g); เมื่อ obj เป็นตัวแปรอะเรย์ประเภท Object http://www.siam2dev.com
การบ้านส่งในชั่วโมงต่อไปการบ้านส่งในชั่วโมงต่อไป • จงใช้ interface ชื่อ relation เพื่อเปรียบเทียบกันระหว่างคลาส List โดยใช้จำนวนโหนดในคลาส List เป็นหลักในการเปรียบเทียบ list1 = {1,2,4,5}; list2 = {1,3}; แสดงว่า list1 > list2 http://www.siam2dev.com
การบ้านส่งในชั่วโมงต่อไปการบ้านส่งในชั่วโมงต่อไป 4. จงใช้คุณสมบัติ inner class เพื่อสร้างคลาส DoublyLinkedList เพื่อจัดการกับการเพิ่มโหนด ลบโหนด ท่องโหนดของโครงสร้างข้อมูลแบบ Doubly Linked List http://www.siam2dev.com