30
หลักการออกแบบและใช้งานคลาส

หลักการออกแบบและใช้งานคลาสvishnu/progmeth/... · •เมธอดที่มี side effect คือ เมธอดที่โค้ดของมันเปลี่ยนค่าที่มองเห็นได้

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

หลกการออกแบบและใชงานคลาส

Actor

• ใหเราสรางออบเจกตได

• แลวท างานอยางใดอยางหนงใหกบโปรแกรมอนๆได

• เชน Scanner, Random

Utility

• มแตคาคงทกบ static method ใหเรยกใช

• เชน Math

หลกการออกแบบ

• ชอคลาสตองเปนค านาม

• ชอคลาสตองสอใหเรารวาจะท าอะไรกบออบเจกตของคลาสนนไดบาง– ตวอยาง ถาท าโปรแกรมเกยวกบการจายเงนเดอน เราไมควรสรางคลาสคลาสเดยวทท าทกอยาง อยาง PaycheckProgram

– แตเราควรเขยน Paycheck ขนมา แลวนยามเมธอดทเปลยนคาหรอจดการ Paycheck ได แลวจงน า Paycheck ออบเจกตไปใชในคลาสทเรารน main

• ถาเกดคลาสมเมธอดทท าหนาทไมคอยเกยวของกน เราควรแยกคลาสนนออกเปนสองคลาส ใหแตละคลาสเรยกเมธอดทเกยวกนภายในคลาสเทานน– ท าใหโปรแกรมดงายขน แกงายขน

– แตวาคลาสหนงจะตองใชอกคลาสหนง ถามมากๆอาจเปนปญหา

– ดงนนใหแยกคลาสเทาทจ าเปนเทานน

• เวลาเขยนเมธอดตางๆ ถาเปนเมธอดทมหลกการท างานเหมอนๆกนอยแลว หวเมธอดกตองเขยนใหเปนแนวเดยวกน

Immutable class• เปนคลาสทมแต accessor เมธอดเทานน

– ตวอยางคอ String เมอออบเจกตทเปน String ถกสรางขนมาแลว จะไมมวนเปลยน เพราะไมมเมธอดในคลาส String ทจะเปลยนคาอะไรของString ออบเจกตไดเลย

String name = “John”;

String uppercase = name.toUpperCase(); // name ไมเปลยนนะ

• ขอดของคลาสประเภทนคอ เอา ref ของออบเจกตใหคนอนใชงานไดโดยไมตองกงวลวาคาจะเปลยน

Side effect• เมธอดทม side effect คอ เมธอดทโคดของมนเปลยนคาทมองเหนไดแมวาเมธอดจะรนเสรจไปแลว เชน คาของ instance variable

ตวอยางเชน public class BankAccount{

….

public void transfer(double amount, BankAccount other){

balance = balance –amount;

other.deposit(amount);

}

}

เปลยนคาตวแปรใน this

เปลยนคาตวแปรในออบเจกตอกตวดวย

ขอควรระวง

• ถาใชออบเจกตเปนพารามเตอรของเมธอด เราเปลยนคาภายในออบเจกตนนได การเปลยนแปลงจะยงอยแมวาเมธอดจะรนเสรจแลว

• แตวา ถาพารามเตอรของเมธอดเปน primitive type เราจะเปลยนคายงไง กจะมผลอยแคในเมธอดเทานน

• ดตวอยาง

• สมมตเราเปลยนเมธอด transfer เปนแบบน public void transfer(double amount, double otherBalance){

balance = balance –amount;

otherBalance = otherBalance + amount;

}

แลวไปเรยกใชงานแบบน

double savingBalance = 1000;

myAccount.transfer(500,savingBalance);

System.out.println(savingBalance);

ตอนเขาไปรนเมธอด มนจะถอวารบคาเขาไปเทานน ตวตนฉบบไมเปลยน

อยาใชพารามเตอรเปนททด

• ถงเราจะรวา พารามเตอรในเมธอด ทเปน primitive type นน จะไมมผลกบภายนอก แตกไมควรใชมนเปนททด

public void deposit(double amount){

amount = balance + amount;

} อยางนจะท าใหพารามเตอรทเราเอาเขามา เปลยนคา ท าใหใชคาผดจากทตองการไดภายในเมธอดน ท าใหเพอนทมาใชโปรแกรมเราตอสบสนดวย

ถาตองการทด สราง local variable ขนมาใหมภายในเมธอดเลยดกวา

ขอควรระวงอกอยาง• ระวงจะลบหรอเปลยนขอมลทไมสมควรเปลยน เชน

public class GradeBook{

public void addStudents(ArrayList<String> names){

while(names.size()>0){

String a_name = names.remove(0);

add(a_name);

}

}

}

ตวอารเรยลสตตนฉบบจะถกลบดวย ดงนนจะเอาไปใชงานทอนในโปรแกรมอกไมไดแลว

ขางลางนผด เพราะอะไร?

public class BankAccount{

….

public void transfer(double amount, BankAccountother){

balance = balance –amount;

double newBalance = other.balance +amount;

other = new BankAccount(newBalance);}

}

a.transfer(100,b);a

b

balance = 500

balance = 500

ตอนเมธอดรน จะรบ ref ของ b เขาไป ท าใหเกดอก ref ขนมา

other a

b

balance = 400

balance = 500

other balance = 600

this

สรปวา b ไมเปลยนเลยถาเขยนแบบน

precondition

• คอสงทตองเปนจรงกอนทเมธอดจะถกเรยกใช ถาไมเปนจรง เจงแน

• เชน เมธอด deposit ตองรบเลขทไมเปนลบเทานน• ตามปกต ควรจะเขยนเปนสวนหนงของคอมเมนไว จะไดเอาไวเชค

/**Deposit money tothe bank account.@param amount the amount to deposit(Precondition: amount >=0)

*/

public void deposit(double amount){…}

• ถาเมธอดถกเรยกโดยท precondition ของมนยงไมเปนจรง– เราอาจตรวจแลว throw exception ได (เดยวไดเรยนเอง)– หรอเราอาจปลอยเลยตามเลย เพราะถอวาคนเรยกเมธอดผดเองทไมไดเรยกตาม precondition

– เดยวกอน ยงมอกวธส าหรบ java

assertion

Public double deposit(double amount){

assert amount >= 0;

balance = balance + amount;

}

สามารถสง enable/disable ได ท าใหแยกสวนนออกจากโปรแกรมได

ถา enable อย แลวได false โปรแกรมจะหยดท างาน แลว throw AssertionError

Java –ea MainClass

• ท าให error ชดเจนแบบน จะไดรตววาเขยนผด และรบแก

• ดกวามา if แลว return กลบ โดยไมท าอะไร เพราะอนนคนรนจะไมเหนวาโปรแกรมผดเลย

postcondition

• ไดคา return value ทถกตอง• ออบเจกตเปลยนไปตามทตองการ/**

Deposit money tothe bank account.(Postcondition: getBalance() >= 0)@param amount the amount to deposit(Precondition: amount >=0)

*/

public void deposit(double amount){…}

Class invariant

• คอสงทเปนจรงเสมอหลงจากสรางออบเจกตแลว ไมวาเมธอดอะไรจะโดนเรยกกเปนจรงอย

• ถาเรารวา class invariant คออะไร เรากตรวจโปรแกรมเราไดวาขณะนนเขยนถกอยหรอไม

public class BankAccount{

double balance;

/**Construct a bank account with a given balance.@param initialBalance the money in the account at the time it is open.(Precondition: initialBalance >=0)

*/public BankAccount(double initialBalance){

balance = initialBalance;}

/**Deposit money tothe bank account.(Postcondition: getBalance() >= 0)@param amount the amount to deposit(Precondition: amount >=0)

*/

public void deposit(double amount){…}

มาดโคดของ BankAccount กนอกท

/**Withdraws money from the bank account.@param amount the amount to withdraw

*/

public void withdraw(double amount){…}

/**Gets the current balance of the bank account.@return the current balance

*/

public double getBalance(){…}

• เราสงเกตไดวา ตงแตสรางออบเจกต คา getBalance() >= 0 เสมอแนนอน ดจากprecondition ของทกเมธอด แลวกสงเกตดดวยวา หลงจากแตและเมธอดถกเรยกแลว ยงเปนจรงอยหรอเปลา

• เอาคา invariant นไปเขยนบรรยายเปนคอมเมนซะ

/**

(Invariant: getBalance() >= 0)

*/public class BankAccount{…}

Static method

• ไมตองสรางออบเจกต กเรยกใชไดเลย เชนเมธอดใน utility class อยาง Math

• สรางขนเพอลดการเขยนโคด อยางทเรยนตอนปหนงนนแหละ แตเมธอดแบบนจะไมตองใชเปลยนหรออานคาของออบเจกตไง

• หลายๆเมธอดเปน static เพราะวามนเลนกบ primitive type เชนตวเลข ซงเราสรางออบเจกตไมได

• เรยกเมธอดประเภทน ตองเรยกจากการใชชอคลาส

การใชงานอกอยางของ static method

• ใชเมอเราไมตองการเปลยนคลาสทมอยแลว หรอเปลยนคลาสทมอยแลวไมได

public class Geometry{

public static double area(Rectangle rect){

return rect.getWidth()*rect.getHeight();

}

} เปนของจาวา เราเปลยนไมได เลยรบเปนพารามเตอรของเมธอดของคลาสใหมแทน ใหเมธอดเปน static เพราะเรามออบเจกตอยแลว คอตว Rectangle

หรอใชเพอ access/mutate ตวแปรทเปน static

• ใชส าหรบจดการกบตวแปรของคลาส ทแชรกนระหวางทกออบเจกตในคลาสนน

วธ initialize static variable

• ไมท าอะไร มนกมคา default เอง

• Assign คา ตอนทเรา declare มนprivate static int x = 1000;

• อกวธคอใช static initialization block

Static import

import static java.lang.System.*;

import static java.lang.Math.*;

double r = sqrt(PI);

out.println(r);

ท าใหไมตองเขยนยาว และโคดอานงายขน

วธ initialize instance variable• ใชคา default

• ใช constructor

• เขยนคา default เอง ตอน declare ตวแปรนน

public class Coin{

private double value =1;

}

คานจะเปน default ตอนสรางทกออบเจกตของคลาสน

• ใช initialization block

public class Coin{private double value ;static int shared;{

value =1;}

static{

shared = 1; }

…}