Trong bài viết này là demo nhỏ về việc áp dụng tính Đóng Gói (Encapsulation) trong Java. Bạn có thể áp dụng làm thử ví dụ của tôi để rút ra được bài học cũng như kinh nghiệm khi sử dụng tính đóng gói.

Demo này giải đáp cho câu hỏi của bạn conangngongcuong@gmail.com

Em chào a, Em đang có một thắc mắc hy vong a sẽ giải đáp giup e. Tính thừa kế trong java:theo e thấy thì hàm get/set nó được dùng như hàm nhập và xuất.Thế thì trong trường hợp nào thì mình dùng get/set,trường hợp nào thì mình dùng nhập/xuất và cách sử dụng của nó.Nếu a có tài liệu nào về get/set trong thừa kế thì cho e xin với. Hy vọng sẽ nhập được hồi âm sớm nhất của a Cảm ơn a nhiều
Để lấy ví dụ cho vấn đề này, chúng ta sẽ thử lập trình về đề tài "1 Garage đỗ xe ô tô".

Trước khi viết các đoạn mã xử lý để mô tả lại cách thức hoạt động của các đối tượng trong thế giới thực bằng Java code, chúng ta phải làm rõ các thông tin cũng như vai trò của từng đối tượng.

Với đề tài ta có:
+ Garage ô tô, bao gồm: tên garage, số lượng xe tối đa....
+ Ô tô, bao gồm: tên xe, chủ xe, biển số....

Với từng đối tượng, chúng ta phải thiết kế các thuộc tính và phương thức phù hợp ứng với vai trò và chức năng của nó. Garage ô tô có thể cho phép 1 ô tô đỗ trong bãi nhưng không có thể chạy hay tăng tốc chẳng hạn....Điều đó có nghĩa rằng, chúng ta phải thiết kế các phương thức độc lập và được đóng gói vào class phù hợp, class này sẽ có nhiệm vụ thực thi các chức năng đó.

Xây dựng các Object Models

Car Model:


/**
 *
 * @author code4lifevn
 */
public class Car {
    private String name;
    private String nameOfOwner;
    private String licenseNumberPlate;
    private boolean isParked;
    
    public Car() {
        isParked = false;
    }
    
    public void setParkedStatus(boolean isParked) {
        this.isParked = isParked;
    }
    
    public boolean isParked() {
        return this.isParked;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLicenseNumberPlate() {
        return licenseNumberPlate;
    }

    public void setLicenseNumberPlate(String licenseNumberPlate) {
        this.licenseNumberPlate = licenseNumberPlate;
    }

    public String getNameOfOwner() {
        return nameOfOwner;
    }

    public void setNameOfOwner(String nameOfOwner) {
        this.nameOfOwner = nameOfOwner;
    }

    @Override
    public String toString() {
        StringBuilder carInfoBuilder = new StringBuilder();
        carInfoBuilder.append("Car Name: ").append(this.name).append("\n");
        carInfoBuilder.append("Name Of Owner: ").append(this.nameOfOwner).append("\n");
        carInfoBuilder.append("License Number Plate: ").append(this.licenseNumberPlate).append("\n");
        carInfoBuilder.append("Parked: ").append(this.isParked);
        return carInfoBuilder.toString();
    }
    
}


Garage Model:

import java.util.ArrayList;
import java.util.List;


/**
 *
 * @author code4lifevn
 */
public class Garage {

    private String name;
    private int amount;
    private List<Car> cars;

    public Garage(String name, int amount) {
        this.name = name;
        this.amount = amount;
        cars = new ArrayList<Car>(amount);
    }

    public void accept(Car car) {
        if (cars.size() >= amount) {
           System.out.println("Garage is full, can not accept " + car.getLicenseNumberPlate());
           return;
        }
        car.setParkedStatus(true);
        cars.add(car);
        System.out.println("Car: " + car.getLicenseNumberPlate() + " has been parked!");
    }
    
    public void reject(String licenseNumberPlate) {
        for (Car car : cars) {
           if(licenseNumberPlate.equalsIgnoreCase(car.getLicenseNumberPlate()) ) {
              cars.remove(car);
           }
        }
    }
    
    public void showAllCars() {
        for (Car car : cars) {
           System.out.println(car);
           System.out.println("=======");
        }
    }
    
    public List<Car> getAllCars() {
        return this.cars;
    }

    public int getAmount() {
        return amount;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}


Class Main:

/**
 *
 * @author code4lifevn
 */

public class Main {

    public static void main(String[] args) {
        Garage garage = new Garage("My Garage", 10);
        Car audi = new Car();
        audi.setName("Audi Q3");
        audi.setNameOfOwner("Do Manh");
        audi.setLicenseNumberPlate("15B1-14298");

        Car civic = new Car();
        civic.setName("Honda Civic 2013");
        civic.setNameOfOwner("Do Manh");
        civic.setLicenseNumberPlate("15B1-123456");

        Car bentley= new Car();
        bentley.setName("Bentley Flying Spur Mulliner 2013");
        bentley.setNameOfOwner("Do Manh");
        bentley.setLicenseNumberPlate("15B1-1234567");

        garage.accept(civic);
        garage.accept(bentley);
        garage.accept(audi);

        garage.showAllCars();

        garage.reject("15B1-123456");
        System.out.println("After Rejecting");
        System.out.println("====");
        garage.showAllCars();
    }
}


Ví dụ trên giúp bạn phần nào hiểu cách lập trình OOP qua những dòng code sử dụng tính bao đóng và chia tách chức năng theo từng đối tượng cụ thể.

Chúc bạn học tốt và nắm vững được kỹ thuật này!
Xem bài viết: Những khái niệm lập trình OOP cơ bản (P.1) - Tính Đóng Gói

10 nhận xét:

  1. carInfoBuilder.append("Car Name: ").append(this.name).append("\n"); Mình nghi ngờ doạn code này có thể thực hiện được.

    public class Car

    .....

    public class Garage {
    private String name;

    private int amount;

    private List cars;

    Viết như thế này mình biết bạn chả hiểu gì về đóng gói cả

    Trả lờiXóa
  2. Hi bạn, đoạn code trên có gì khó hiểu. Và comment của bạn mình cũng không hiểu rõ ý bạn muốn nói tới ở đây là gì. Nếu bạn là người rành OOP, có kinh nghiệm lâu năm, cho mình cao kiến, khai sáng cho mình vấn đề này đi :)

    Trả lờiXóa
  3. Hi, mình hiểu ý của bạn. Tính đóng gói được áp dụng trong những trường hợp như sau:
    + Đóng gói Modle
    + Đóng gói nghiệp vụ


    Trong bài toán trên, nghiệp vụ xử lý dành cho Car chứ không phải Bicyle hay AirPlan hoặc Food.


    Mình sử dụng Generic để cụ thể hóa kiểu dữ liệu được phép thao tác là gì để nghiệp vụ xử lý đúng với kiểu dữ liệu đó. Park cho Car, chứ không phải Park cho Food/Bicycle.


    Theo mình nhìn nhận có thể bạn đang mới bắt đầu tìm hiểu về Design Pattern hoặc đại loại những kỹ thuật nào đó liên quan tới lousely-coupling. Thực ra tính đóng gói nó không quá cứng nhắc tới việc sử dụng Model nào trong tầng Bussiness. Sự phụ thuộc nói chính xác ra nó phụ thuộc nhiều hơn ở tầng abstract (Abstract Class, Interface).


    Lấy ví dụ, đơn giản hơn không sử dụng class Car, mình có như sau:
    public class Test {

    private List links = new ArrayList();
    }



    Vậy theo bạn class trên cũng không phải đóng gói? vì nó sử dụng 1 Kiểu dữ liệu khác ngoài class hiện hành?. Và nếu như để làm theo đúng cách bạn nghĩ thì mình sẽ phải làm thế này:


    public class Test {
    private List links = new ArrayList();


    private class MyCustomString {
    //do something..
    //This is so crazy about Encapsulation

    }

    }


    Oh, my god ^^

    Trả lờiXóa
  4. 2) Có khi nào bạn nghĩ là mình sẽ sử dụng những class mình viết ra không, vd: như muốn sử dụng lại class Car thì bạn chỉ cần copy lại doạn code class Car là được. Còn nếu bạn muốn sử dụng đầy đủ class Garage thì bắt buộc bạn phải copy thêm class Car mang theo. Đó chính là sức mạnh của Encapsulation.

    Trả lờiXóa
  5. Sử dụng lại những class mình đã viết

    Trả lờiXóa
  6. Những ý kiến bạn đưa ra rất hay và mới lạ...Nhưng có lẽ từ lúc biết tới kỹ thuật này của bạn mình phải đi chứng minh lại mô hình MVC, Bean, Spring và tất cả nền tảng của Java thôi :)

    Trả lờiXóa
  7. 1) post lại cái link ở trên http://msdn.microsoft.com/en-us/library/vstudio/dd460654.aspx
    2) từ ngữ thì rất là đa nghĩa, nếu cứ chat như vậy thì khó mà giải thích cách hiểu của mình cho bạn. Khi nào mình có thời gian mình sẽ quay lại giải thích thêm.

    Trả lờiXóa
  8. hi,

    vd: như trong đoạn code của bạn, trong class Car mình viết thêm Ham() {name = '3"}. Và trong class Garage mình sẽ gọi hàm này -> Garage vẫn có thể làm thay đổi thuộc tính của Car vậy mặc dù bạn đã để private.

    Trả lờiXóa
  9. Ham() ở đây là gì? Constructor? Hay Phương thức? (Trong OOP không có khái niệm hàm).


    Nếu mình hiểu Ham() của bạn là Constructor thì mình chịu không có lời nào để giải thích nữa và không hiểu bạn đang cố đóng gói cái gì. Nếu ý của bạn đúng là đang sử dụng Constructor thì mọi mã lệnh sẽ được thực thi ngay khi đối tượng dó được khởi tạo. (Điều mà ai cũng biết). Thuộc tính name nằm trong class Car và mã lệnh gọi tới sẽ thực thi name = "3" bất kể trong hay ngoài class.


    Nếu mình hiểu Ham() là 1 phương thức đơn giản nào đó được bạn cố tình đặt thêm vào trong class Car thì việc sửa đổi thông tin/trạng thái của đối tượng là điều dĩ nhiên.


    Việc sửa đổi mã lệnh có thể tạm chia làm 2 loại:
    + Cố tình. (Hack/Crack Bytecode)

    + Chủ động. (do chủ ý của người viết code).


    Về chủ động, người viết code có thể thiết kế model và đưa ra những tính năng cho model đó.


    Về việc cố tình, có thể trực tiếp sửa bytecode để làm thay đổi trạng thái đối tượng (khá dễ dàng) hoặc sử dụng Reflection. Cả Java hay C# đều không có tính bảo mật tốt, nếu không thực sự được chăm chút mã hóa.



    Khi bạn đưa ra vấn đề này không hiểu bạn có nắm được các Access Modifier hay không nhưng những điều bạn đưa ra thực sự rất mơ hồ.


    Bạn hãy đưa ra 1 mô hình hoàn chỉnh và những mảnh mã thực sự clear để mọi người đều hiểu và cùng học hỏi chứ không nên đưa ra những câu lệnh lẻ tẻ kèm theo những vấn đề mà ai cũng biết nó sẽ là như vậy. :)

    Trả lờiXóa
  10. Khài niệm hack/crack theo mình hiểu là sự vượt qua hàng rào bảo mật nào đó. Khài niệm "crack source code" là khái niệm của riêng bạn và chỉ bạn sử dụng thôi. Vì đã là source code thì còn bảo mật gì nữa.

    Thôi không nói miên man nữa. Bạn hiểu theo cách của bạn, mình hiểu theo cách của mình, miễn sao từ cách hiểu áp dụng hiệu quả vào công việc của mỗi người là được rồi.

    Trả lờiXóa

 

code4lifevn team

Thanh niên nghiêm túc :)

Name: Manh Do

Age: years old

Job: Senior Java and Mobile Developer

Country: VietNam

Name: Hung Nguyen

Age: years old

Job: Android Developer

Country: VietNam

Name: Trung PH

Age: years old

Job: Senior iOS and Android Developer

Country: VietNam

Name: Điệp NT

Age: years old

Job: Senior .Net and Android Developer

Country: VietNam