PHƯƠNG THỨC GHI VẢ ĐỌC

Một phần của tài liệu Giáo trình lập trình hướng đối tượng java (Trang 61 - 83)

Thong thường, các biển trường sẽ được đóng/bao gói với quyền truy cập.

(access modifiers) 6 các mức độ khác nhau. Để cập nhật và truy xuất chúng, ta thường dùng đến các phương thức đọc, ghỉ để định nghĩa ra một kênh giao tiếp (từ bên ngoài) tới chúng được an toàn và bảo mật. Do vậy, phạm vỉ truy cập của các phương thức này thường là từ mọi nơi của chương trình (được xác định bởi từ khóa publie).

Các phương thire ghi (setters) được gọi là phương thức thay đôi

(mutator methods), chúng được dùng để thiết lập các giá trị cho các biển trường.

Trong quá trình gán giá trị, cần có sự kiêm tra tính hợp lệ dữ liệu trước dé an toàn hơn. Còn các phương thức đọc (getters), hay được gọi là phương thức truy xuất (accessor methods), ching được dùng dé lay (get) giá trị của các biến trường.

Thông thường, mỗi một biến thành viên bỗ từ truy cập là private sẽ có.

một cặp phương thite getter, setter.

„._ Ví dụ 4.9: Sử dụng phương các phương thức set/getters để đọc và ghỉ các biến thể hiện hiện có bổ từ truy cập private.

pe * file name: LopChinh. java

*/

Package ctu.vdlinh.chapter4;

class HinhTron {

int x = 50, y= 50; //tọa độ tâm x, y private double bk; //ban kinh

public HinhTron(double bk) { this.bk = bk;

public HinhTron(int x, int y, đouble bk) { }

super();

this.x = x; this.y = ys" this.bk = bk;

zt public double getBk()r{

return\ bk3

} public void\setBk(double bk) { if (bk < 0.0) {

System.err.print]n("Bán kính phải có giá trị dương. ");

this.bk = bk; }

public double tinhDienTich() { }

return Math.PI * Math.pow(bk, 2);

- public class LopChinh {

public static void main(string[] args) {

HinhTron ht1 = new HinhTron(2@, 20, 10.379);

System.out.printf( "Diện tích hình tròn với bán kính= %..2f là:

%.2f\n", - ht1.getBk(), ht1. tỉnhDienTich());

ht1.setBk(5.5); // đổi bk =

System.ứut.printf( “Diện tớch hỡnh trũn với bỏn kớnh= %.2f là:

%.2f\n", - ht1.getBk(), h1. tinhD1enTich());

} ie

4.6 PHƯƠNG THỨC HUY

Khác với C and C++, sự thu hồi bộ nhớ được Java tự động thực hiện bởi Garbage collector, giúp cho ta thực hiện các yêu câu trước khi đôi tượng bị hủy (destructors), đú phương thức fùnalize(). Ta cú thể ghi chồng lại phương thức finalize() này để quan lý các đối tượng trong chương trình.

„.... Ví dụ 4.10: Viết chương trình dé định nghĩa kiểu lớp Cirele, sau đó đếm số đối tượng được tạo ra/ được huỷ khi chạy chương trình.

package ctu.vdlinh.chapter4;

"

* Created đate: 17-01-2011

* @author Vu Duy Linh

* File name: DemDoiTuong. java M

class Circle {

private int x, y; double radius; // biến thể hiện

private static int numOfCircles = @; // biến lớp

mà -Một số phương thức thể hiện ---

public Circle() {

ap super();

x=y =1; radius = 6.5;

nunOƒCircLes++;

} public Circle(int x, int y, double radius) { super();

this.x = x; this.y = y5 this.radius = radius;

numofCircles++s

} public double getRadius() { return radius;

} public void setRadius(double radius) { this.radius = radius;

= public static int getNumofcircle() { return numofcircles;

public double circumference() { +

return (get_2Pi() * radius);

void showInfo(String name){ }

System.out.printf(name + “ban kinh = %5.2f, va chu vi =

%10.4f \n", getRadius(); circumference());

} protected void finalize() throws Throwable { super. finalize();

= -numofcireles;

}

PE =

public static void setNumOfCircles(int numofCircles) {

Một Số phương thức lớp --

Circle.numOfCircLes = nunOfCircles;

private static double get_2Pi() { }

return 2 * Math.PT;

public class DenDoiTuong {

public static void main(String[] args) { Circle c1 = new Circle();

Circle c2 = new Circle(1, 29, 4.50);

new Circle(58, 59, 12.25);

Circle c3

Circle c4 = new Circle(166, 56, 7.89);

System.owt.print1n(*"Số đối tượng được tạo là:

Circle.getNumofcircle());

c1.shouTnfo("Hình tròn c1 có: *);

c2.showTnfo("Hình tròn c2 có: ");

c3.shouTnfo("Hình tròn c3 có: *);

c4.showTnfo("Hình tròn c4 có: ");

c3 = nu11;

Runtine.getRuntime().gc(); // System.gc();

system.runFinalization();

S5ystem.ứut.print1n("Số đối tượng cũn lại sau khi hủy là: "+

Circ1e.getNunoƒCircLe());

}

Kết quả chương trình:

Console £3

<terminated> DemDoiTuong [Java Application] C:\Program Files\Java\jdk1.7.0_45\) Số đối tượng

Hình trồn c1 và chủ vi = — 3.1416

Hình tròn c2 va chu vi 28.2743

Hình tron c3 va chu vi 76.9690

Hình tròn c4

Số đối tượng và chu vi = 49.0088

lại sau khi hủy là: 3

4/7 TRUYEN THAM SỐ.

Khi gọi phương thức có chứa tham số, ta cần phải truyền đối số cho nó.

Trong Java, vì không có khái niệm con trỏ, nên tắt cả các kiểu dữ liệu đều được truyền bằng tham trị (pass by value).

Đối với biến kiểu nguyên thủy (primitive type variable): Khi ta ra lời gọi phương thức thì Java sẽ tạo một bản sao của biển tham số thực và bản sao này sẽ truyền cho tham số hình thức £> giá trị của biến bản sao tham số thực này sẽ bằng với giá trị của biến tham số hình thức nhưng không ảnh hưởng đến giá trị

của tham số thực ban đầu.

Đối với biến kiểu tham chiéw/ déi tugng (reference! object type variable):

Java cũng truyền đối số bằng trị, nghĩa là giá trị (của) biến tham chiều của tham số thực sẽ được truyền cho biến tham chiếu của tham số hình thức. Như vậy, biến tham số thực và tham số hình thức đều tham chiếu đến cùng một đối tượng nên giá trị của chúng sẽ ảnh hưởng đến nhau.

Ví dụ 4.11: Minh họa truyền tham số đối với kiểu dữ liệu nguyên thủy và

đối tượng.

package ctu.vdlinh.chapter4 ye * Created date: 17-01-2011

* File name: PassParametters. java class HinhTron {

private int bk;

private String trThai;

public void setBk(int bk) { this.bk = bk;}

public void setTrThai(String trthai) { this.trThai = trThai;

@0verride }

public String toString() {

return "trạng thái; \"" + trThai“+ "\*'và bán kín

+ bk;

} public class PassParametters {

static void, passBy0bject(HinhTron ht2) {

ht2.setTrThai("Đã cập nhật!"); // thay đổi giá trị ht2, setBk(46) ;

} static void passByPrimitive(int a) { a = 200; // thay đổi giá trị của tsht public static void main(String[] args) { †

int x = 18; // tham số thực

System.out.print]n("‹*ằ Truyền tham số đối với kiểu nguyên thủy:");

System.out.primtln("\tằ›> Trước khi gọi phương thức passByPrimitive, x= " + x);

pass8yPrimitive(x);

System.out.println("\tằằ> Sau khi gọi phương thức passByPrimitive, x=" + x);

System.out.print1n("\n<*› Truyền tham số đối với kiểu đối tượng:");

HinhTron ht1 = new HinhTron(); - // tham số thực ht1.setTrThai ("Ban đầu."); _ ht1.setBk(388);

System.out.print1n(*\t>>> Trước khi gọi phương thức

passByObject, ht1:\n\t\t " + ht1.toString());

passBy0bject(ht1) ;

System.out.print1n("\n\t››>Sau khi gọi phương thức passByObject,hti:\n\t\t "+ hti.toString());

}

Nết quả chương trình:

-<terminated> PassParametters [Java Application] C:\Program Files\ava\jdk1.7.0 45°

<*› Truyền tham số đối với kiểu nguyên thủy: >>> Trước khi gọi phương thức passByPrimitive, x= 100

>>> Sau khi gọi phương thức passByPrimitive, x= 109

<*› Truyền tham số đối với kiểu đối tượng: >>> Trước khi gọi phương thức passByObject, ht1: trạng thái: "Ban đầu." và bán kính" 389

>>ằsau khi gọi phương thức pass8y0bject, h1:

trạng thái: "Đã cập nhật!” và bán kính= 409.

.. Sau đây là hình minh họa cho việc truyền đối với kiểu nguyên thủy và kiểu đối tượng trong ngôn ngữ Java

Ví dụ 4.12: Định nghĩa một lớp người dùng số thực (Complex), rồi sử

dụng nó đề tính các phép tính cụ thể.

i/Rile: Complex. java

package ctu.vdlinh. chapter;

yt * @author Robert Sedgewick

* @author Kenvin Wayne

* website: www.princeton.edu

public class Complex {

private final double re; // the real part private final double im; // the imaginary part

// create a new object with the given real and imaginary parts public Complex(double real, double imag) {

re = real;

im = imag;

} // return a stoing representation-of the invoking Complex object public String toString() {

if (im if (re

if (im < @) return

8) return re + "";

6) return im +

return re + "4" +

7/ return abs/modulus/magnitude and angle/phase/argument }

public double abs() {

// Math.sqrt(re*re + imtim) return Math.hypot(re, im);

public double phase() { }

// between -pi and pi return Math.atan2(im, re);

// return a new Complex object whose value is (this + b) public Complex plus(Complex b) {

Complex a = this; // invoking object double real = a.re + b.re;

double imag = a.im + b. im;

return new Complex(real, imag);

} // return a new Complex object whose value is (this - b) public Complex minus (Complex b) {

Complex a = this;

double real = a.re - b.re double imag = a.im - b. im;

return new Complex(real, imag);

} // return a new Complex object whose value is (this * b) public Complex times (Complex b) {

Complex a = this;

double real = a.re * b.re - a.im * b.im;

double imag = a.re * b.im + a.im * b.re;

return new Complex(real, imag);

} // scalar multiplication

// return a new object whose value is (this * alpha) public Complex times(double alpha) {

return new Complex(alpha * re, alpha * im);

+ // return a new Complex object whose value is the conjugate of this public Complex conjugate() {

return new Complex(re, -im);

// return a new Complex object whose value is the reciprocal of this }

public Complex reciprocal() {

đouble scale = re*re + in*im;

return new Conplex(re / scale, -im / scale);

// return the real or imaginary part public double re() {

return re;

public double im() { }

return im;

// return a/b }

public Complex divides (Complex b) { Complex a = this;

return a.times(b.reciprocal())5

/* return a new Complex object whose value is the complex }

exponential of this */

public Complex exp() {

return new Complex(Math.exp(re) * Math:€s(im), Math.exp(re)* Math, sin(im))5

+ /* return a new Complex object’ whose value is the complex sine of this */

public Complex sin() {

return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));

} /* return a new Complex object whose value is the complex cosine of this */

public Complex cos() {

return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im))5

a /* return a new Complex object whose value is the complex tangent of this */

public Complex tan() {

return sin().divides(cos());

J/ a static version of plus}

public static Complex plus(Complex a, Complex b) { double real = a.re + b.re;

double imag = a.im + b.im;

Complex sum = new Complex(real, imag);

return sum;

: Conp1exTest,

package_ctu.vd1inh..chapter4;

+ * website: www.princeton.edu

* pata type for complex numbers.

* The data type is “immutable” so once you create and initialize

* a Complex object, you cannot change it. The "final" keyword

* when declaring re and im enforces this rule, making it a

* compile-time error to change the .re or .im fields after

* they've been initialized.

public class ConplexTest { Sự

// sample client for testing

public static void main(string[] args) { Complex a = new Complex(5.0, 6.0);

Complex b = new Complex(-3.0, 4.6);

System.out.printin("a ays

system.out.print1n("b b);

system.out.println("Re(a) a.re())3 system. out. printIn(*"Im(a) a.im());

system.out.printin("b + a = system.out.printin("a - b = System.out.println(*a * b =

b.plus(a));

a.minus(b));

a.times(b));

+ b.times(a))5 a.divides(b));

system.out.printin("b * a =

System.out.printin("a / b

System.out.println("(a / b) *b_ = " + a.divides(b).times(b));

System.owt.print1n("conj (a) =" + a-conjugate())5 System.out.print1n(*a| =" + a.abs())5

System. out.printIn("tan(a) =" + a.tan());

} }

Kết quả chương trình:

a = 5.0 + 6.04

b 3.0 + 4.01

Re(a) 8

Im(a) = 6.0

b+a .0.+ 18.01

a-b 8.0 + 2.01

a*b 39.0 + 2.01

b*a 39.0 + 2.01

aso = 0.36 - 1.521 (a/b) *b =5.0+6.0i

conj(a) 5.0= 6.01

lal = 7,810249675906654

tan(a) 6.685231390246571E-6 + 1.0000103108981198i

4.8. TRUYỀN THÔNG ĐIỆP GIỮA CÁC ĐÓI TƯỢNG

Trong phương pháp lập trình hướng đối tượng, khi xây dựng mô hình các đối tượng, chúng ta cân phải xem xét đến những khả năng tương tác có thể có giữa chúng trong không gian bài toán đang xem xét. Sự tương tác này được thực hiện thông qua việc gửi

yêu cầu, nhận và đáp ứng yêu cầu giữa chúng. Sự yêu

cầu và đáp ứng yêu cầu như thể được thực hiện bởi cơ chế truyền thông điệp (messages).

“9: result S =

takeOrder

Benjamin Sean

Hình 4.8 Sự tương tác giữa đối tượng Benjamin va Sean

Ví dụ 4.13: Trong hệ thống, các đối tượng sẽ tương tác với nhau theo.

một kịch bản sẵn có, chăng hạn như khách hàng Benjamin gửi một thông điệp cho người bán hàng là Sean với yêu cầu *Tôi muốn đặt mua một bộ salon có 6 món, được giao vào thứ Từ tuần tới". Tiếp đến, Sean sẽ xem xét xem có thẻ đáp ứng được cho Benjamin không (như gọi về cửa hàng, kiểm tra hàng và lịch

) rồi sẽ thông báo kết quả đặt hàng lại cho anh ta là “Ok: Đồng ý, còn mặt hàng này” hoặc “Not ok: Xin lỗi, mặt hàng này đã hết”.

Message ơ zÊ Arguments va

takeOrder (so:

address, del iver

Benjamin

N— object Object —~

Hình 4.9 Sự tương tác giữa các đối tương bằng message

Với tình huống trong thể giới thực như trên, ta có cấu trúc lớp nhân viên,

Customer, và lớp người bán hàng, SalesPerson, như sau:

Class Customer

Customer

Attributes:

address name

at address

purchase) budget

Methods:

purchaseQ) {send a purchase request to a salesperson}

getBudget() {return budget}

“SalesP. ss SalesPerson Attributes:

: a name

Methods:

takeOrder) — {

check with warehouse on stock availability check with warehouse on delivery schedule if ok then {

instruct warehouse to deliver stock(address, date) return ok

else return not ok i

Với lớp Customer, tạo ra đối tượng khách hàng có tên là “Benjamin” '

như sau:

Benjamin as an Object Attributes:

name= "Benjamin"

address = "1, Robinson Road”

budget = 2000 Methods:

getBudget() {return budget}

purchase() {send a purchase request to a salesperson}

Với lớp SalesPerson, tạo ra đối tượng và 02 đối tượng bán hang la “Sean”

và *Sara” như sau:

Sean as an Object

Attributes:

name= "Sean"

Methods:

takeOrder)) {

check with warehouse on stock availability

check with warehouse on delivery schedule

ifok then {

instruct warehouse to deliver stock(address, date)

return ok

} else return not ok

Sara as an Object

Attributes:

name= "Sara"

Methods:

takeOrder() {

check with warehouse on stock availability check with warehouse on delivery schedule

if ok then {

instruct warehouse to deliver stock(address, date) return ok

} else return not ok

Như vậy: Thông điệp là một lời gọi phương thức từ một đối tượng gửi

thông điệp (message-sending object) tới đối tượng nhận thông điệp

(message-recciving object).. Đối tượng gửi thông điệp được gọi là sender còn đối tượng nhận thông điệp gọi là receiver. Ở ví dụ trên, Benjamin là sender còn

Sean la receiver.

Một thông điệp thi bao gồm 3 thành phi

~_ Định danh của đối tượng tiếp nhận thông điệp (receiver),

~ Tên phương thức (của đối tượng receiver),

..— Và các đối số (arguments) được truyền vào đẻ cung cấp thêm thông tin cần thiết để thực hiện phương thức trên.

Benjamin as an Object

Attributes:

name = "Benjamin"

address = "1, Robinson Road"

budget = 2000 Methods

purchase() {

Sean.takeOrder("Benjamin”, "sofa", "1, Robinson Road","12 November")

getBudget() {return budget} 1

Một thông điệp là hợp lệ nếu đối tượng receiver có một phương thức

(method) tương ứng với tên phương thức và các đối số phù hợp (nếu có) của thông điệp. Như vậy, đối tượng sender sẽ thực thi một phương thức nào đó, chăng hạn purchase(){...}, mà trong đó có lời gọi một phương thức của

tượng reciever để truyền thông điệp nhu takeOrder() {

Sean as an Object Attributes:

name = "Sean"

Methods

takeOrder(who, stock, address, date) { check with warehouse on stock availability check with warehouse on delivery schedule if ok then {

instruct warehouse to deliver stock to address on date return ok

} else return not ok

Trong lập trình hướng đối tượng, đối tượng Benjamin và Sean được tuân

theo nguyên tắc che dấu thông tin (information hiding) vi Scan lim như thế nào để đáp ứng được yêu cầu của Benjamin là điều mà Benjamin không thể biết

hoặc bị che khuất

... Môhình khách — chủ (elient đối tượng luôn có dạng mô hình

reciever là phía server.

server): Trong quá trình trao đổi thông tin

\y; Đối tượng sender là phía client còn

đụ yes/no available?

send

Sean ok <⁄

Hình 4.10 Quá trình liên lạc giữa các đối tượng theo mô hình client-server

Benjamin

'Thông điệp mang lại 02 lợi ích quan trong, đó là: Các hành vi của một đối tượng được thể hiện thông qua phương thức của nó, và do đó (ngoài truy cập bien trực tiếp) nó hỗ trợ tắt cả các tương tác có thé có giữa các đối tượng. Và đôi

tượng không cần phải ở trong cùng một quá trình (proeess) hoặc thậm chí trên

cùng một máy đề gửi và nhận thông điệp qua lại với nhau.

Các thông điệp này được sử dụng trong biểu đồ tương tác (interaction diagram) dé thé hign cho các đối tượng tương tác với nhau. Biểu đô tương tác này là sự tổng quát hóa của cả biểu d6 twin tyr (sequence diagram) và biểu đồ

(collaboration diagram) được chuyên biệt từ nó.

j"""—~. ‘sd Retreive Balance (nt accountNumber) ni }

myBank : Bank ledger : accountLedger [acent: customerAccount

‘getBalance(aNum)

Hình 4.11 Minh họa messages trong sơ đồ tuần tự

(Source: Tech-ICT.com)

49 GÓI

Gói (package) là một cách để gom chung các kiểu dữ liệu (lớp, giao dign,...) c6 liên hệ với nhau thành một nhóm với phạm vi quyển truy xuất nhất định - việc quan trọng đồi với những dự án phát triền theo phương pháp lập trình

hướng đối tượng. Ngoài ra, nó còn được dùng đẻ phân vùng không gian tên (name space) để tránh xung đột tên (name) trong quá trình viết mã lệnh.

PockageName

ClassinThisPackage

Hình 4.12 Ky higu UML cua package

Hệ thống phân cấp của package được xác định thông qua từ khóa

package thường đứng trước việc định nghĩa cho một lớp.

Cú pháp: paekagetên gói[tên gói con];

class MyClass{

/imembers

Ví dụ 4.1

package mypackage.core;

class MyStack{

J/members

ạo lớp MyStack thuộc vào gói mypackage.core

Để sử dụng các lớp được định nghĩa trong package nào đó, ta nạp chúng vào lớp/giao diện hiện hành, UsingMyStack, thông qua tir khéa import như các cách sau:

= Nap tit cả các lớp trong mypackage.core vào lớp hiện hành

UsingMyStack:

import mypackage.core.*;

class UsingMyStack { J/members

- Hoặc chỉ nạp lớp MyStack vào lớp UsingMyStack như lệnh sau: }

import mypackage.core. MyStack;

class UsingMyStack{

members

truy xuất trực tiếp chúng thông qua dấu chấm phân cách trong

hệ thống phân cấp của gói:

class UsingMyStack{

mypackage.core, MyStack stackl =

new mypackage.core. MyStack();

Khi sử dụng gói, dự án cần phải được xác định phạm vi truy cập ở mức } } lớp, mức các thành viên lớp/giao diện của các gói sao cho cho có thẻ truy xuất được với nhau.

Dưới đây là bảng mô tả phạm vỉ truy cập của các thành viên giữa các lớp

€ oi:

Quyền truy xuất. KG Biches eee peat

Pham vi =

Ở cùng lớp. Yes Yes Yes Yes

Ở khác lớp và cùng gói Yes Yes Yes No

Ở lớp con và cùng gói Yes Yes Yes No

Ở lớp con và khác gói Yes Yes No No

O khác lớp và khác gói Yes No No No

'Ví dụ 4.15: Viết chương trình giải phương trình bậc 2 gồm hai lớp được.

đặt trong hai gói khác nhau như hình 4.13

Hf Package Explorer 2 BSle 7

4 ÊJ VD_PTB2 4 Bsc

4 {8 ctuvdlinh.obp.packagel 4 [) PTB2java

4 © PTB2

aa 2b

& PTB2(double, double, double) ac

© tinhPTB20 : void 4 { ctuvdlinh.obp.package2

4 {D) MainClassjave

Q MainClass

6Ÿ main(String[]) : void

4 BÀ, JRE System Library [J2v2SE-1.7]

Hình 4.13. Cấu trúc dự án giải phương trình bậc hai

Một phần của tài liệu Giáo trình lập trình hướng đối tượng java (Trang 61 - 83)

Tải bản đầy đủ (PDF)

(255 trang)