Wednesday, July 4, 2007

Tìm hiểu lập trình hướng đối tượng (OOP) - 5

Ta lại tiếp tục chủ đề hướng đối tượng với khái niệm tham chiếu, copy đối tượng
Từ các phần trước ta đã biết qua các khái niệm lớp, đối tượng, và các cách làm viêc với chúng
Trong phần này ta sẽ tìm hiểu về hoạt động của đối tượng
Xét lớp sau




package test1;

public class ClassA {
private String field;

/**
* @return the field
*/
public String getField() {
return field;
}

/**
* @param field the field to set
*/
public void setField(String field) {
this.field = field;
}
}



Khi chúng ta khởi tạo một đối tượng thông qua toán tử new

ClassA objA = new ClassA();

Hệ thống sẽ cung cấp một vùng nhớ tương ứng với lớp ClassA, và vùng nhớ này sẽ được trỏ đến bởi tham chiếu objA
Sau đó

objA.setField("field 1");

thì giá trị "field 1" sẽ được lưu vào vùng nhớ đã được cấp thông qua tham chiếu objA

System.out.println("1. a: " + a.getField()); sẽ cho kết quả là 1.a : field 1

Với một khởi tạo khác

ClassA objB = new ClassA();

Hệ thống sẽ tiếp tục cung cấp một vùng nhớ tương ứng với lớp ClassA và vùng này sẽ được trỏ đến bởi tham chiếu objB
Nếu ta tiếp tục thao tác như trên thì không có gì xảy ra, nhưng giả sử ta thực hiện như sau

objB = objA;
hoặc ClassA objB = objA;

thì khi này hệ thống không cung cấp vùng nhớ để tham chiếu objB trỏ vào mà hệ thống sẽ cho tham chiếu objB trỏ vào vùng nhớ mà tham chiếu objA đã trỏ vào. Và khi đó, 2 tham chiếu objA, objB sẽ có chung một vùng nhớ, những thay đổi từ 2 tham chiếu này sẽ được đưa vào vùng nhớ trênm và sẽ 'ảnh hưởng' lẫn nhau


ClassA objA = new ClassA();
objA.setField("field 1");
ClassA objB = objA;

System.out.println("1. a: " + objA.getField()); => 1. a: field 1
System.out.println("1. b: " + objB.getField()); => 1. b: field 1

objA.setField("field 2");
System.out.println("2. a: " + objA.getField()); => 2. a: field 2
System.out.println("2. b: " + objB.getField()); => 2. b: field 2

objB.setField("field 3");
System.out.println("3. a: " + objA.getField()); => 3. a: field 3
System.out.println("3. b: " + objB.getField()); => 3. b: field 3


Như vậy toán tử new sẽ khởi tạo vùng nhớ mới cho đối tượng, và toán tử = chỉ đơn giản là cùng trỏ hai tham chiếu vào cùng một vùng nhớ chứ không mang tính copy hoàn toàn đối tượng

Như vậy, với lớp ClassA ta có thể viết tiếp một phương thức copy 'bản thân' nó thành một đối tượng mới như sau


package test1;

public class ClassA {
private String field;

/**
* @return the field
*/
public String getField() {
return field;
}

/**
* @param field the field to set
*/
public void setField(String field) {
this.field = field;
}

public ClassA clone(){
ClassA obj = new ClassA();
obj.setField(this.field);
return obj;
}
}




Phương thức clone() sẽ copy hoàn toàn một đối tượng hiện tại


ClassA objA = new ClassA();
objA.setField("field 1");
ClassA objB = objA;
ClassA objC = objA.clone();

System.out.println("1. a: " + objA.getField()); => 1. a: field 1
System.out.println("1. b: " + objB.getField()); => 1. b: field 1
System.out.println("1. c: " + objC.getField()); => 1. c: field 1

objA.setField("field 2");
System.out.println("2. a: " + objA.getField()); => 2. a: field 2
System.out.println("2. b: " + objB.getField()); => 2. b: field 2
System.out.println("2. c: " + objC.getField()); => 2. c: field 1

objB.setField("field 3");
System.out.println("3. a: " + objA.getField()); => 3. a: field 3
System.out.println("3. b: " + objB.getField()); => 3. b: field 3
System.out.println("3. c: " + objC.getField()); => 3. c: field 1

Tìm hiểu lập trình hướng đối tượng (OOP) - 4

Trong phần này ta bàn lại vấn đề Kế thừa

- Trong thế giới thực tồn tại nhiều loại đối tượng có các thuộc tính và hành vi tương tự hoặc liên quan đến nhau ví dụ như Giáo viên, Học sinh, Công nhân,... họ đều là người, có các đặc điểm chung như: có họ tên, có nghệ nghiệp,... những đặc điểm chung của đối tượng giáo viên, học sinh,... có thể được sử dụng chung ở một mức độ nào đó
- Hơn nữa, với sự phát triển của CNTT, đã làm xuất hiện nhu cầu sử dụng lại các mã nguồn đã viết

Việc sử dụng lại mã nguồn thường thông qua một số cách như sau:
+ Sử dụng lại thông qua copy: copy mã nguồn cần sử dụng lại vào mã nguồn mới
. Tốn công, dễ nhầm lẫn trong mã nguồn
. Khó sửa lỗi do tồn tại nhiều phiên bản
+ Sử dụng lại thông qua quan hệ has_a: chuyển lớp cần sử dụng lại thành một thành phần của lớp mới


class Person {


private String name;


private Date bithday;


public String getName() {


return name;


}


...


}


class Employee {


private Person me;


private double salary;


public String getName() {


return me.getName();


}


...


}





. Việc đưa lớp cần sử dụng lại trở thành thành phần của lớp mới có nhược điểm là chưa đủ mềm dẻo, phải viết lại giao diện mới, việc truy xuất các thuộc tính của lớp sử dụng lại sẽ không thực sự mềm dẻo
Ví dụ


class Assistant {


private Employee me;


}


class Manager {


private Assistant ass;


...


}




+ Sử dụng lại thông qua cơ chế “kế thừa”
. Dựa trên quan hệ is_a
. Thừa hưởng lại các thuộc tính và phương thức đã có của lớp cha
. Chi tiết hóa cho phù hợp với mục đích sử dụng mới
. Thêm các thuộc tính mới
. Thêm hoặc hiệu chỉnh các phương thức


class Employee extends Person {


private double salary;


public boolean setSalary(double sal) {


...


salary = sal;


return true;


}


}




Với cấu trúc kế thừa thế này ta có thể cho phép kế thừa ở mức nhiều tầng như Person -> Employee -> Assistant -> Manager

Tìm hiểu lập trình hướng đối tượng (OOP) - 3

Trong phần này ta sử dụng các ví dụ bằng Java để mô tả lại các phần đã đi qua với class

Định nghĩa lớp

Lớp được định nghĩa bởi


class class_name {


...


}



Ví dụ:


class MyDate {


}


Thuộc tính, phương thức và kiểm soát truy cập


class MyDate {


private int year, mon, day;


public int getYear() {


return year;


}


public boolean setYear(int y) {


...


}


...


}




Phương thức khởi tạo (constructor)
Dữ liệu nên được khởi tạo trước khi sử dụng

Phương thức khởi tạo

* Là phương thức đặc biệt được gọi tự động sau khi tạo ra đối tượng
* Nhằm mục đích chính là khởi tạo cho các thuộc tính của đối tượng
* Có tên trùng với tên lớp
* Không nhận giá trị trả lại
* Mỗi khi đối tượng được tạo ra bởi toán tử new
* Hệ thống sẽ gọi phương thức tạo constructor mặc định => là một phương thức rỗng (không làm gì cả)




Ví dụ: Constructor rỗng

class SayMsg {


}…


SayMsg msg = new SayMsg();




class SayMsg {


SayMsg() {


System.out.println(”Hello”);


}


SayMsg(String s) {


System.out.println(s);


}


}

...
SayMsg msg1 = new SayMsg();
SayMsg msg2 = new SayMsg(”Java”);


Lưu ý: nếu phương thức tạo mặc định SayMsg() không được khai báo và trong class cũng không khai báo thêm phương thức tạo nào khác thì với câu lệnh "SayMsg msg1 = new SayMsg();" hệ thống sẽ tự động gọi đến phương thức tạo mặc định. Nhưng nếu trong class không khai báo phương thức tạo mặc định mà có khai báo một phương thức tạo khác (vd: SayMsg(String s){...}) thì câu lệnh "SayMsg msg1 = new SayMsg();" sẽ bị báo lỗi ngay

Ta có thêm một dạng phương thức tạo khác, đó là khởi tạo đối tượng từ một đối tượng khác


public class MyItem {


private int attribute;


public MyItem () {...}


public MyItem (MyItem i) {


// khởi tạo đối tượng từ một đối tượng cùng lớp khác


attribute= i.getAttribute();


}


public int getAttribute(){


return attribute;


}


...


}


Tìm hiểu lập trình hướng đối tượng (OOP) - 2

Phần này ta tìm hiểu tiếp về các thành phần của lớp: con trỏ this, phương thức khởi tạo, thành phần tĩnh

Các thành viên chính của Lớp

Con trỏ this

Đây là thành viên đặc biệt của lớp, nó thể hiện chính bản thân của lớp đang chứa nó. Ví dụ trong lớp But, ta có thể sử dụng cú pháp this.mau để thể hiện thuộc tính mau của lớp bút

Phương thức tạo (Constructor)

Phương thức này được sử dụng để khởi tạo tất cả các thuộc tính của một lớp, phương thức này trùng tên với tên lớp và đặc biệt là không có kiểu trả về như những phương thức bình thường khác

Ví dụ:



public class But{


public But(String m, boolean t){


this.mau = m;


this.trangthai = t;


}


}



Thành viên tĩnh (static)


public class A{


private static String a1;


public static String a2;


public static void getSomeThing(){}


}




Thuộc tính tĩnh là một thuộc tính đặc biệt, nó có phạm vi trong toàn lớp định nghĩa bởi từ khóa static, tức là, với một thuộc tính bình thường, nó chỉ có thể thể hiện được khi ta khởi tạo một đối tượng là thể hiện của lớp đó, ví dụ lớp But ở trên, thuộc tính mau chỉ có thể được khởi tạo (cấp phát vùng nhớ, gán giá trị) khi ta khởi tạo một đối tượng butObj và thuộc tính mau chỉ có "phạm vi" trong đối tượng butObj, thuộc tính mau của butObj1 sẽ khác butObj2 (vùng nhớ được cấp phát khác nhau). Riêng thuộc tính a1,a2 sẽ khác thuộc tính mau, 2 thuộc tính này có "phạm vi" toàn lớp, nó không được truy xuất qua đối tượng mà trực tiếp qua lớp chứa nó: A.a2, khi run lớp A mặc dù chưa có đối tượng nào được khởi tạo nhưng a1, a2 đã được khởi tạo, cấp phát vùng nhớ

Xét tiếp đoạn ví dụ sau



public class A{


private static byte a1 = 1;


public void changeStatic(byte a){


A.a1 += a;


System.out.print(A.a1);//không quan tâm nhiều câu lệnh này, nó chỉ làm nhiệm vụ in a1 ra


}


}


Khi run, lớp A được khởi tạo, thuộc tính tĩnh a1 sẽ có 1 vùng nhớ và được gán giá trị là 1
Ta khởi tạo 2 đối tượng của lớp A và thực hiện gọi phương thức changeStatic, phương thức này làm nhiệm vụ đưa vào một số a, cộng số này vào a1 sau đó in a1 ra.


A obj1 = new A();
A obj2 = new A();
obj1.changeStatic(2);
obj2.changeStatic(3);
obj1.changeStatic(1);



Khi đó kết quả in ra của đoạn trên là


3 // 1 + 2
6 // 3 + 3
7 // 6 + 1

Tìm hiểu lập trình hướng đối tượng (OOP) - 1

Giới thiệu

Hướng đối tượng (object orientation) cung cấp một kiểu mới để xây dựng phần mềm. Trong kiểu mới này, các đối tượng (object) và các lớp (class) là những khối xây dựng trong khi các phương thức (method), thông điệp (message), và sự thừa kế (inheritance) cung cấp các cơ chế chủ yếu.

Nếu bạn chưa bao giờ sử dụng một ngôn ngữ OOP thì trước tiên bạn nên nắm vững các khái niệm của OOP hơn là viết các chương trình. Bạn cần hiểu được đối tượng (object) là gì, lớp (class) là gì, chúng có quan hệ với nhau như thế nào, và làm thế nào để các đối tượng trao đổi thông điệp (message) với nhau,…


Trừu tượng hóa (Abstraction)

Trừu tượng hóa là một kỹ thuật chỉ trình bày những các đặc điểm cần thiết của vấn đề mà không trình bày những chi tiết cụ thể hay những lời giải thích phức tạp của vấn đề đó. Hay nói khác hơn nó là một kỹ thuật tập trung vào thứ cần thiết và phớt lờ đi những thứ không cần thiết.



Ví dụ những thông tin sau đây là các đặc tính gắn kết với con người:

* Tên
* Tuổi
* Địa chỉ
* Chiều cao
* Màu tóc


Giả sử ta cần phát triển ứng dụng khách hàng mua sắm hàng hóa thì những chi tiết thiết yếu là tên, địa chỉ còn những chi tiết khác (tuổi, chiều cao, màu tóc, ..) là không quan trọng đối với ứng dụng. Tuy nhiên, nếu chúng ta phát triển một ứng dụng hỗ trợ cho việc điều tra tội phạm thì những thông tin như chiều cao và màu tóc là thiết yếu.

Sự trừu tượng hóa đã không ngừng phát triển trong các ngôn ngữ lập trình, nhưng chỉ ở mức dữ liệu và thủ tục. Trong OOP, việc này được nâng lên ở mức cao hơn – mức đối tượng. Sự trừu tượng hóa được phân thành sự trừu tượng hóa dữ liệu và trừu tượng hóa chương trình.

Đối tượng (object)

Các đối tượng là chìa khóa để hiểu được kỹ thuật hướng đối tượng. Bạn có thể nhìn xung quanh và thấy được nhiều đối tượng trong thế giới thực như: con chó, cái bàn, quyển vở, cây viết, tivi, xe hơi... Trong một hệ thống hướng đối tượng, mọi thứ đều là đối tượng. Một bảng tính, một ô trong bảng tính, một biểu đồ, một bảng báo cáo, một con số hay một số điện thoại, một tập tin, một thư mục, một máy in, một câu hoặc một từ, thậm chí một ký tự, tất cả chúng là những ví dụ của một đối tượng.

Rõ ràng chúng ta viết một chương trình hướng đối tượng cũng có nghĩa là chúng ta đang xây dựng một mô hình của một vài bộ phận trong thế giới thực. Tuy nhiên các đối tượng này có thể được biểu diễn hay mô hình trên máy tính.
Một đối tượng thế giới thực là một thực thể cụ thể mà thông thường bạn có thể sờ, nhìn thấy hay cảm nhận được. Tất cả các đối tượng trong thế giới thực đều có trạng thái (state) và hành động (behaviour).
Ví dụ:


Đối tượng: xe đạp
Trạng thái: bánh răng, bàn đạp, dây xích
Hành động: tăng tốc, giảm tốc, chuyển bánh răng



Các đối tượng phần mềm (software object) có thể được dùng để biểu diễn các đối tượng thế giới thực. Chúng được mô hình sau khi các đối tượng thế giới thực có cả trạng thái và hành động. Giống như các đối tượng thế giới thực, các đối tượng phần mềm cũng có thể có trạng thái và hành động. Một đối tượng phần mềm có biến (variable) hay trạng thái (state) mà thường được gọi là thuộc tính (attribute; property) để duy trì trạng thái của nó và phương thức (method) để thực hiện các hành động của nó. Thuộc tính là một hạng mục dữ liệu được đặt tên bởi một định danh (identifier) trong khi phương thức là một chức năng được kết hợp với đối tượng chứa nó.

OOP thường sử dụng hai thuật ngữ mà sau này Java cũng sử dụng là thuộc tính (attribute) và phương thức (method) để đặc tả tương ứng cho trạng thái (state) hay biến (variable) và hành động (behavior). Tuy nhiên C++ lại sử dụng hai thuật ngữ dữ liệu thành viên (member data) và hàm thành viên (member function) thay cho các thuật ngữ này.

Xét một cách đặc biệt, chỉ một đối tượng riêng rẽ thì chính nó không hữu dụng. Một chương trình hướng đối tượng thường gồm có hai hay nhiều hơn các đối tượng phần mềm tương tác lẫn nhau như là sự tương tác của các đối tượng trong trong thế giới thực.

Đối tượng (object) là một thực thể phần mềm bao bọc các thuộc tính và các phương thức liên quan.

Đối tượng xe đạp phần mềm cũng có các phương thức để thắng lại, tăng nhịp đạp hay là chuyển đổi bánh răng. Nó không có phương thức để thay đổi tốc độ vì tốc độ của xe đạp có thể tính ra từ hai yếu tố số vòng quay và bánh răng hiện tại. Những phương thức này thông thường được biết như là các phương thước thể hiện (instance method) bởi vì chúng tác động hay thay đổi trạng thái của một đối tượng cụ thể.

Một đối tượng cụ thể được gọi là một thể hiện (instance).

Lớp (Class)

Trong thế giới thực thông thường có nhiều loại đối tượng cùng loại. Chẳng hạn chiếc xe đạp của bạn chỉ là một trong hàng tỉ chiếc xe đạp trên thế giới. Tương tự, trong một chương trình hướng đối tượng có thể có nhiều đối tượng cùng loại và chia sẻ những đặc điểm chung. Sử dụng thuật ngữ hướng đối tượng, chúng ta có thể nói rằng chiếc xe đạp của bạn là một thể hiện của lớp xe đạp. Các xe đạp có một vài trạng thái chung (bánh răng hiện tại, số vòng quay hiện tại, hai bánh xe) và các hành động (chuyển bánh răng, giảm tốc). Tuy nhiên, trạng thái của mỗi xe đạp là độc lập và có thể khác với các trạng thái của các xe đạp khác. Trước khi tạo ra các xe đạp, các nhà sản xuất thường thiết lập một bảng thiết kế (blueprint) mô tả các đặc điểm và các yếu tố cơ bản của xe đạp. Sau đó hàng loạt xe đạp sẽ được tạo ra từ bản thiết kế này. Không hiệu quả nếu như tạo ra một bản thiết kế mới cho mỗi xe đạp được sản xuất.
Trong phần mềm hướng đối tượng cũng có thể có nhiều đối tượng cùng loại chia sẻ những đặc điểm chung như là: các hình chữ nhật, các mẫu tin nhân viên, các đoạn phim, … Giống như là các nhà sản xuất xe đạp, bạn có thể tạo ra một bảng thiết kế cho các đối tượng này. Một bảng thiết kế phần mềm cho các đối tượng được gọi là lớp (class).

Trở lại ví dụ về xe đạp chúng ta thấy rằng một lớp Xedap là một bảng thiết kế cho hàng loạt các đối tượng xe đạp được tạo ra. Mỗi đối tượng xe đạp là một thể hiện của lớp Xedap và trạng thái của nó có thể khác với các đối tượng xe đạp khác..

Lớp Xedap sẽ khai báo các thuộc tính thể hiện cần thiết để chứa đựng bánh răng hiện tại, số vòng quay hiện tại, .. cho mỗi đối tượng xe đạp. Lớp Xedap cũng khai báo và cung cấp những thi công cho các phương thức thể hiện để cho phép người đi xe đạp chuyển đổi bánh răng, phanh lại, chuyển đổi số vòng quay, ..

Lớp (class) là một thiết kế (blueprint) hay một mẫu ban đầu (prototype) định nghĩa các thuộc tính và các phương thức chung cho tất cả các đối tượng của cùng một loại nào đó.
Một đối tượng là một thể hiện cụ thể của một lớp.

Sau khi bạn đã tạo ra lớp xe đạp, bạn có thể tạo ra bất kỳ đối tượng xe đạp nào từ lớp này. Khi bạn tạo ra một thể hiện của lớp, hệ thống cấp phát đủ bộ nhớ cho đối tượng và tất cả các thuộc tính thể hiện của nó. Mỗi thể hiện sẽ có vùng nhớ riêng cho các thuộc tính thể hiện của nó.

Ngoài các thuộc tính thể hiện, các lớp có thể định nghĩa các thuộc tính lớp (class attribute). Một thuộc tính lớp chứa đựng các thông tin mà được chia sẻ bởi tất cả các thể hiện của lớp. Ví dụ, tất cả xe đạp có cùng số lượng bánh răng. Trong trường hợp này, định nghĩa một thuộc tính thể hiện để giữ số lượng bánh răng là không hiệu quả bởi vì tất cả các vùng nhớ của các thuộc tính thể hiện này đều giữ cùng một giá trị. Trong những trường hợp như thế bạn có thể định nghĩa một thuộc tính lớp để chứa đựng số lượng bánh răng của xe đạp.Tất cả các thể hiện của lớp Xedap sẽ chia thuộc tính này. Một lớp cũng có thể khai báo các phương thức lớp (class methods). Bạn có thể triệu gọi một phương thức lớp trực tiếp từ lớp nhưng ngược lại bạn phải triệu gọi các phương thức thể hiện từ một thể hiện cụ thể nào đó.

Thuộc tính (Attribute)

Các thuộc tính trình bày trạng thái của đối tượng. Các thuộc tính nắm giữ các giá trị dữ liệu trong một đối tượng, chúng định nghĩa một đối tượng đặc thù.

Một thuộc tính có thể được gán một giá trị chỉ sau khi một đối tượng dựa trên lớp ấy được tạo ra. Một khi các thuộc tính được gán giá trị chúng mô tả một đối tượng. Mọi đối tượng của một lớp phải có cùng các thuộc tính nhưng giá trị của các thuộc tính thì có thể khác nhau. Một thuộc tính của đối tượng có thể nhận các giá trị khác nhau tại những thời điểm khác nhau.

Phương thức (Method)

Các phương thức thực thi các hoạt động của đối tượng. Các phương thức là nhân tố làm thay đổi các thuộc tính của đối tượng.

Các phương thức xác định cách thức hoạt động của một đối tượng và được thực thi khi đối tượng cụ thể được tạo ra.Ví dụ, các hoạt động chung của một đối tượng thuộc lớp Chó là sủa, vẫy tai, chạy, và ăn. Tuy nhiên, chỉ khi một đối tượng cụ thể thuộc lớp Chó được tạo ra thì các phương thức sủa, vẫy tai, chạy, và ăn mới được thực thi.
Các phương thức mang lại một cách nhìn khác về đối tượng. Khi bạn nhìn vào đối tượng Cửa ra vào bên trong môi trường của bạn (môi trường thế giới thực), một cách đơn giản bạn có thể thấy nó là một đối tượng bất động không có khả năng suy nghỉ. Trong tiếp cận hướng đối tượng cho phát triển hệ thống, Cửa ra vào có thể được liên kết tới phương thức được giả sử là có thể được thực hiện. Ví dụ, Cửa ra vào có thể mở, nó có thể đóng, nó có thể khóa, hoặc nó có thể mở khóa. Tất cả các phương thức này gắn kết với đối tượng Cửa ra vào và được thực hiện bởi Cửa ra vào chứ không phải một đối tượng nào khác.

Thông điệp (Message)

Một chương trình hay ứng dụng lớn thường chứa nhiều đối tượng khác nhau. Các đối tượng phần mềm tương tác và giao tiếp với nhau bằng cách gởi các thông điệp (message). Khi đối tượng A muốn đối tượng B thực hiện các phương thức của đối tượng B thì đối tượng A gởi một thông điệp tới đối tượng B.
Ví dụ đối tượng người đi xe đạp muốn đối tượng xe đạp thực hiện phương thức chuyển đổi bánh răng của nó thì đối tượng người đi xe đạp cần phải gởi một thông điệp tới đối tượng xe đạp.
Đôi khi đối tượng nhận cần thông tin nhiều hơn để biết chính xác thực hiện công việc gì. Ví dụ khi bạn chuyển bánh răng trên chiếc xe đạp của bạn thì bạn phải chỉ rõ bánh răng nào mà bạn muốn chuyển. Các thông tin này được truyền kèm theo thông điệp và được gọi là các tham số (parameter).

Tính bao gói (Encapsulation)

Trong đối tượng xe đạp, giá trị của các thuộc tính được chuyển đổi bởi các phương thức. Phương thức changeGear() chuyển đổi giá trị của thuộc tính currentGear. Thuộc tính speed được chuyển đổi bởi phương thức changeGear() hoặc changRpm().
Trong OOP thì các thuộc tính là trung tâm, là hạt nhân của đối tượng. Các phương thức bao quanh và che giấu đi hạt nhân của đối tượng từ các đối tượng khác trong chương trình.Việc bao gói các thuộc tính của một đối tượng bên trong sự che chở của các phương thức của nó được gọi là sự đóng gói (encapsulation) hay là đóng gói dữ liệu.
Đặc tính đóng gói dữ liệu là ý tưởng của các nhà thiết các hệ thống hướng đối tượng. Tuy nhiên, việc áp dụng trong thực tế thì có thể không hoàn toàn như thế. Vì những lý do thực tế mà các đối tượng đôi khi cần phải phơi bày ra một vài thuộc tính này và che giấu đi một vài phương thức kia. Tùy thuộc vào các ngôn ngữ lập trình hướng đối tượng khác nhau, chúng ta có các điều khiển các truy xuất dữ liệu khác nhau.

Tính thừa kế (Inheritance)

Hệ thống hướng đối tượng cho phép các lớp được định nghĩa kế thừa từ các lớp khác. Ví dụ, lớp xe đạp leo núi và xe đạp đua là những lớp con (subclass) của lớp xe đạp. Như vậy ta có thể nói lớp xe đạp là lớp cha (superclass) của lớp xe đạp leo núi và xe đạp đua.
Các lớp con thừa kế thuộc tính và hành động từ lớp cha của chúng. Ví dụ, một xe đạp leo núi không những có bánh răng, số vòng quay trên phút và tốc độ giống như mọi xe đạp khác mà còn có thêm một vài loại bánh răng vì thế mà nó cần thêm một thuộc tính là gearRange (loại bánh răng).
Các lớp con có thể định nghĩa lại các phương thức được thừa kế để cung cấp các thi công riêng biệt cho các phương thức này. Ví dụ, một xe đạp leo núi sẽ cần một phương thức đặc biệt để chuyển đổi bánh răng.

Che giấu thông tin (information hiding) là việc ẩn đi các chi tiết của thiết kế hay thi công từ các đối tượng khác.

Thừa kế (inheritance) nghĩa là các hành động (phương thức) và các thuộc tính được định nghĩa trong một lớp có thể được thừa kế hoặc được sử dụng lại bởi lớp khác.

Lớp cha (superclass) là lớp có các thuộc tính hay hành động được thừa hưởng bởi một hay nhiều lớp khác.

Lớp con (subclass) là lớp thừa hưởng một vài đặc tính chung của lớp cha và thêm vào những đặc tính riêng khác.

Các lớp con cung cấp các phiên bản đặc biệt của các lớp cha mà không cần phải định nghĩa lại các lớp mới hoàn toàn. Ở đây, mã lớp cha có thể được sử dụng lại nhiều lần.

Tính đa hình (Polymorphism)

Một khái niệm quan trọng khác có liên quan mật thiết với truyền thông điệp là đa hình (polymorphism). Với đa hình, nếu cùng một hành động (phương thức) ứng dụng cho các đối tượng thuộc các lớp khác nhau thì có thể đưa đến những kết quả khác nhau.

Chúng ta hãy xem xét các đối tượng Cửa Sổ và Cửa Cái. Cả hai đối tượng có một hành động chung có thể thực hiện là đóng. Nhưng một đối tượng Cửa Cái thực hiện hành động đó có thể khác với cách mà một đối tượng Cửa Sổ thực hiện hành động đó. Cửa Cái khép cánh cửa lại trong khi Cửa Sổ hạ các thanh cửa xuống. Thật vậy, hành động đóng có thể thực hiện một trong hai hình thức khác nhau. Một ví dụ khác là hành động hiển thị. Tùy thuộc vào đối tượng tác động, hành động ấy có thể hiển thị một chuỗi, hoặc vẽ một đường thẳng, hoặc là hiển thị một hình.
Đa hình có sự liên quan tới việc truyền thông điệp. Đối tượng yêu cầu cần biết hành động nào để yêu cầu và yêu cầu từ đối tượng nào. Tuy nhiên đối tượng yêu cầu không cần lo lắng về một hành động được hoàn thành như thế nào.

Đa hình (polymorphism) nghĩa là “nhiều hình thức”, hành động cùng tên có thể được thực hiện khác nhau đối với các đối tượng/các lớp khác nhau.

Xét một ví dụ sau: ta bàn về cây bút, nó có các thuộc tính như màu sắc, trạng thái còn sử dụng được hay không, và tất cả các cây bút thường có một hành động là viết hoặc vẽ một nội dung gì đó, ở đây ta sử dụng ngôn ngữ Java để mô tả lớp đối tượng bút như sau:



public class But {
private String mau; //mau cua cay but
private boolean trangthai; //trang thai cua cay but, con dung duoc hay khong

public void viet(String noidung){
// xu ly viet ra mot chuoi noidung
}
}



Ở đây ta chưa quan tâm đến các từ in đậm, đó chỉ là các kiểu dữ liệu trong các ngôn ngữ lập trình. Ta quan tâm đến mau, trangthai là 2 trang thái, hay thuộc tính của lớp But và viet là hành động hay là phương thức của lớp But.
Các từ khóa private (theo ngôn ngữ Java) cho biết 2 thuộc tính mau, trangthai được 'bao đóng' ở mức riêng tư, các đối tượng khác không thể truy xuất (access) đến các thuộc tính này, và từ khóa public cho biết phương thức viet cho phép các đối tượng khác truy xuất đến nó, phưong thức này sẽ thực hiện một số công việc nhằm mục đích víêt ra một nội dung.

Như vây, ta đã xây dựng được cơ bản một lớp, như đã đề cập ở trên, But chỉ là một lớp, nó cần phải có một đối tượng mới thể hiện được mình
Trong Java ta dùng cú pháp:


But butObj = new But();


để tạo ra một thể hiện của lớp But, như vậy lúc này butObj là một đối tượng thật sự của lớp But, toán tử new có nhiệm vụ khởi tạo và cấp phát một vùng nhớ cho đối tượng butObj.
Với việc khởi tạo đối tượng butObj ta có thể truy xuất đến phương thức viet của đối tượng butObj bằng cú pháp butObj.viet("Hello wordl !") (theo Java), riêng việc truy xuất 2 thuộc tính mau, trangthai thì không thể, vì nó đã được khai báo tính riêng tư(private)

Ta tiếp tục với tính kế thừa và tính đa hình trong OOP với ví dụ trên, ta nhận thấy bút sẽ có rất nhiều lại: bút bi, bút máy, bút chì, cọ...như thế ta sẽ có một mối quan hệ kế thừa mà lớp cha là lớp But và các lớp con là: ButBi, ButMay, ButChi, Co... các lớp này sẽ mang các thuộc tính mau, trangthai và phương thức viet của lớp cha. Khi đó để các lớp con có thể kế thừa, lớp But sẽ được khai báo lại như sau


public class But {
protected String mau; //mau cua cay but
protected boolean trangthai; //trang thai cua cay but, con dung duoc hay khong

public void viet(String noidung){
// xu ly viet ra mot chuoi noidung
}
}




Từ khóa protected cho biết thuộc tính này có thể được kế thừa từ các lớp con thực sự của nó (tức là không kể các lớp "cháu")



public class ButMay extends But{
private String loaimuc; //loai muc cua cay but

public void thaymuc(String muc){
// xu ly thay muc
}
}


Với khai báo trên, lớp ButMay sẽ có các thuộc tính mau, trangthai, loaimuc trong đó 2 thuộc tính đầu được kế thừa từ lớp cha But, lớp ButMay sẽ có 2 phương thức viet, thaymuc với phương thúc viet được kế thừa từ lớp But

Ở đây ta bàn tiếp đến tính đa hình

Giả sử trong lớp But, phương thức viet được định nghĩa như sau:



public void viet(String noidung){
- Viet 'noidung' ra
}
}


Như trên, trong lớp ButMay ta không khai báo lại lớp này, nên bây giờ ta khởi tạo một thể hiện của lớp ButMay


ButMay butmay = new ButMay();

Khi đó nếu ta gọi phương thức butmay.viet("Hello ưorld!") thì nó sẽ "- Viet 'Hello world' ra" y như những gì mà lớp cha But đã khai báo

Giờ đây, trong lớp ButMay ta khai báo như sau



public void viet(String noidung){
- Thay lai mau muc do
- Lam gon noi dung, thay doi noidung = NGUYEND + noidung
- Viet 'noidung' ra
}
}



Khi đó với phương thức butmay.viet("Hello world!") nó không còn đơn giản là viết ra nữa, nó không gọi đến phương thức viết của lớp cha But mà nó gọi đến phương thức viet do lớp con ButMay khai báo -> đây là một thể hiện của tính đa hình