Các lớp lồng nhau (nested classes) trong java


Các lớp lồng nhau (nested classes)

Việc định nghĩa một lớp bên trong một lớp khác được gọi là lớp lồng (nesting). Lớp lồng chỉ nằm trong phạm vi lớp bao quanh nó.Có hai loại lớp lồng:
- Lớp kiểu tĩnh (static)
Lớp kiểu tĩnh được định nghĩa với từ khoá static. Lớp tĩnh có thể truy nhập vào các thành viên của lớp phủ nó thông qua một đối tượng. Do vậy lớp tĩnh thường ít được sử dụng.
- Lớp kiểu không tĩnh (non static)
Lớp bên trong (inner) quan trọng nhất của các lớp lồng. Đó là các lớp non-static. Định nghĩa lớp bên trong chỉ có thể xác định được trong phạm vi lớp ngoài cùng. Lớp bên trong có thể truy nhập tất cả các thành viên của lớp bao nó, song không thể ngược lại. Đoạn chương trình sau mô tả lớp được tạo lập ra sao và sử dụng như thế nào:

PHP Code:

class Outer
{
//Outer class constructor
class Inner
{
//Inner class constructor
}
}

Cú pháp sau đây cho phép truy nhập vào lớp bên trong

PHP Code:

Outer.Inner obj=new Outer().new Inner(); 

Một lớp lồng trong là gì?Như tên của nó đã gợi ý, trong ngôn ngữ Java một lớp lồng trong là một lớp được khai báo trong một lớp khác. Đây là một ví dụ đơn giản:

PHP Code:

    public class EnclosingClass {
...
public class NestedClass {
...
}
}

Thông thường, các lập trình viên giỏi định nghĩa các lớp lồng trong khi lớp lồng trong chỉ có ý nghĩa bên trong bối cảnh của lớp bao bọc bên ngoài. Một số ví dụ phổ biến như sau:

Các trình xử lý sự kiện trong một lớp UI.
Các lớp Helper cho các thành phần UI trong một thành phần UI khác.
Các lớp Adapter để biến đổi bộ phận bên trong của một lớp thành một số dạng khác cho người dùng lớp này.

Bạn có thể định nghĩa một lớp lồng trong là lớp công khai (public), riêng tư (private) hay có bảo vệ (protected). Bạn cũng có thể định nghĩa một lớp lồng trong là lớp final (để ngăn cho nó không bị thay đổi), lớp trừu tượng (abstract) (có nghĩa là nó không thể khởi tạo thành cá thể cụ thể) hoặc lớp tĩnh (static).

Khi bạn tạo ra một lớp static bên trong một lớp khác, bạn đang tạo ra cái được gọi một cách phù hợp nhất là lớp lồng trong. Một lớp lồng trong được định nghĩa bên trong một lớp khác, nhưng có thể tồn tại bên ngoài một cá thể của lớp bao ngoài. Nếu lớp lồng trong của bạn không phải là lớp static, nó chỉ có thể tồn tại bên trong một cá thể của lớp bao ngoài và được gọi một cách phù hợp hơn là lớp bên trong (inner class). Nói khác đi, mọi lớp bên trong là lớp lồng trong nhưng không phải mọi lớp lồng trong là lớp bên trong. Phần lớn các lớp lồng trong mà bạn sẽ gặp phải trong sự nghiệp của bạn sẽ là lớp bên trong hơn là các lớp chỉ đơn giản lồng trong.

Bất kỳ lớp lồng trong nào đều có quyền truy cập vào tất cả các thành viên của lớp bao ngoài, ngay cả khi chúng được khai báo là private.

Định nghĩa các lớp lồng trong

Bạn định nghĩa một lớp lồng trong đúng như bạn định nghĩa một lớp thông thường khác, nhưng bạn thực hiện nó trong một lớp bao ngoài. Một ví dụ như đã bày sẵn là hãy định nghĩa một lớp Wallet bên trong lớp Adult. Cho dù trong thực tế bạn có thể có một Cái ví (Wallet) tách khỏi một Adult, nhưng điều này sẽ không có ích lắm và điều có ý nghĩa hơn là mọi Adult đều có một Wallet (hoặc ít nhất là một thứ gì đó để giữ tiền, nhưng nếu dùng MoneyContainer nghe hơi lạ). Cũng là có nghĩa khi cho rằng Wallet sẽ không tồn tại trong Person, bởi vì một Baby không có ví và tất cả các lớp con của Person sẽ thừa kế nó nếu nó tồn tại trong Person.

Lớp Wallet của chúng ta sẽ khá đơn giản, vì nó chỉ phục vụ để minh họa định nghĩa về một lớp lồng trong: 

PHP Code:

    protected class Wallet {
protected ArrayList bills = new ArrayList();
protected void addBill(int aBill) {
bills.add(new Integer(aBill));
}protected int getMoneyTotal() {
int total = 0;
for (Iterator i = bills.iterator(); i.hasNext(); ) {
Integer wrappedBill = (Integer) i.next();
int bill = wrappedBill.intValue();
total += bill;
}
return total;
}
}
Chúng ta sẽ định nghĩa lớp này bên trong Adult, giống như sau:

PHP Code:

    public class Adult extends Person {
protected Wallet wallet = new Wallet();
public Adult() {
}
public void talk() {
System.out.println("Spoke.");
}
public void acceptMoney(int aBill) {
this.wallet.addBill(aBill);
}
public int moneyTotal() {
return this.wallet.getMoneyTotal();
}
protected class Wallet {
...
}
}

Lưu ý rằng chúng ta đã thêm acceptMoney() để cho phép một Adult nhận thêm tiền. (Xin cứ tự nhiên mở rộng ví dụ để bắt buộc Adult của bạn phải chi tiêu một vài thứ, đó là việc phổ biến trong cuộc sống thực).

Sau khi chúng ta có lớp lồng trong và phương thức acceptMoney() mới, chúng ta có thể sử dụng chúng như sau:

PHP Code:

    Adult anAdult = new Adult();
anAdult.acceptMoney(5);
System.out.println("I have this much money: " + anAdult.moneyTotal());


Xử lý sự kiện rất đơn giản

Ngôn ngữ Java định nghĩa một cách tiếp cận xử lý sự kiện với các lớp kết hợp để cho phép bạn tạo và xử lý các sự kiện của riêng bạn. Nhưng việc xử lý sự kiện có thể đơn giản hơn nhiều. Tất cả những gì mà bạn thực sự cần là một lô gic nào đó để sinh ra một "sự kiện" (mà thực sự không cần phải hoàn toàn là một lớp sự kiện) và một lô gic nào đó để lắng nghe sự kiện và sau đó trả lời một cách thích hợp. Ví dụ, giả sử rằng bất cứ khi nào một Person di chuyển, hệ thống của chúng ta tạo ra (hoặc kích hoạt) một MoveEvent, mà chúng ta có thể chọn xử lý hay không xử lý. Điều này sẽ yêu cầu một số thay đổi cho hệ thống của chúng ta. Chúng ta phải:

Tạo ra một lớp "ứng dụng" (application) để khởi chạy hệ thống của chúng ta và minh họa việc sử dụng lớp bên trong vô danh.

Tạo một MotionListener mà ứng dụng của chúng ta có thể thực hiện và sau đó xử lý các sự kiện trong trình lắng nghe (listener).
  • Thêm một List của các trình lắng nghe vào Adult.

  • Thêm một phương thức addMotionListener() vào Adult để đăng ký trình lắng nghe.

  • Thêm một phương thức fireMoveEvent() vào Adult để nó có thể báo cho trình lắng nghe khi nào thì xử lý sự kiện.

  • Thêm mã vào ứng dụng của chúng ta để tạo ra một Adult và tự đăng ký như là một trình xử lý
Tất cả điều này dễ hiểu. Đây là lớp Adult của chúng ta với các thứ mới thêm: 

PHP Code:

    public class Adult extends Person {
protected Wallet wallet = new Wallet();
protected ArrayList listeners = new ArrayList();
public Adult() {
}
public void move() {
super.move(); fireMoveEvent();
}
...
public void addMotionListener(MotionListener aListener) {
listeners.add(aListener);
}
protected void fireMoveEvent() {
Iterator iterator = listeners.iterator();
while(iterator.hasNext()) {
MotionListener listener = (MotionListener) iterator.next();
listener.handleMove(this);
}
}
protected class Wallet {
...
}
}


Lưu ý rằng bây giờ chúng ta ghi đè move(), đầu tiên gọi move() trên Person, sau đó gọi fireMoveEvent() để báo cho trình lắng nghe trả lời. Chúng ta cũng đã thêm phương thức addMotionListener() để thêm một MotionListener vào một danh sách trình lắng nghe đang hoạt động. Đây là những gì giống với một MotionListener:

PHP Code:

public interface MotionListener {
public void handleMove(Adult eventSource);
}

Tất cả những gì còn lại là tạo ra lớp ứng dụng của chúng ta: 

PHP Code:

    public class CommunityApplication implements MotionListener {
public void handleMove(Adult eventSource) {
System.out.println("This Adult moved: \n" + eventSource.toString());
}
public static void main(String[] args) {
CommunityApplication application = new CommunityApplication();
Adult anAdult = new Adult();
anAdult.addMotionListener(application);
anAdult.move();
}
}

Lớp này thực hiện giao diện MotionListener có nghĩa là nó triển khai thực hiện phương thức handleMove(). Tất cả những điều mà chúng ta làm ở đây là in một thông báo để minh họa những gì xảy ra khi một sự kiện được kích hoạt.


Post a Comment

Mới hơn Cũ hơn