Thứ Ba, 2 tháng 4, 2013

Flyweight

1. Khái niệm

Flyweight pattern sử dụng tính năng chia sẻ để hỗ trợ xử lý số lượng lớn các đối tượng một cách hiệu quả.

2. Vấn đề thực tế

Giả sử chúng ta có một bài toán như sau:

Trong đợt thi tuyển sinh đại học, mỗi trường đều có mức điểm chuẩn khác nhau để đánh giá tiêu chí đạt hay không đạt của thí sinh, giả sử số lượng môn thi là 3, số lượng thí sinh tham gia kỳ thi là 1 triệu, số lượng trường đại học, cao đẳng là 100. Số liệu về điểm thi và thông tin thí sinh được tập trung tại 1 nơi. Yêu cầu đặt ra là in 1 danh sách kết quả thi của toàn bộ các thí sinh theo mẫu cho sẵn (đã bao gồm kết quả đạt hay không đạt). Nếu chúng ta giải bài toán này dùng mô hình lập trình hướng đối tượng, có khả năng chúng ta phải tạo ra khoảng 1 triệu object đại diện cho 1 triệu thí sinh, điều nay sẽ ảnh hướng lớn đến hiệu suất hoạt động của hệ thống vì phải xử lý một lượng dữ liệu tương đối lớn.

Giải pháp nào để thực hiện vấn đề trên mà không phải tạo ra 1 triệu object?

3. Giải pháp

Chúng ta sẽ dùng Flyweight pattern để giải quyết vấn đề trên.

Flyweight pattern là một dạng compound pattern (pattern tổng hợp), do đó chúng ta cần phân tích từng phần và bản chất của Flyweight pattern trước khi ứng dụng vào thực tế.

Thông thường để tăng tốc độ truy xuất của hệ thống, chúng ta hay dùng mô hình cache để thực hiện. Đây cũng là điểm mấu chốt trong Flyweight pattern. 1 triệu object theo đề bài yêu cầu cần có những tính năng chung để có thể cache lại được vì nếu 1 triệu thí sinh đều không có điểm chung thì chắc chắn chúng ta sẽ không sử dụng được Flyweight pattern để giải quyết vấn đề.

Như vậy, câu hỏi đặt ra, đâu là điểm chung của 1 triệu thí sinh?

Khái niệm "điểm chung" ở đây không phải là điểm chung của 1 triệu thí sinh, mà là điểm chung để có thể phân các thí sinh ra thành từng nhóm, ví dụ nếu lấy điểm chung về giới tính thì có thể phân các thí sinh làm 2 nhóm, lấy điểm chung về quê quán thì có thể phân nhóm các thí sinh dựa vào xuất xứ ghi trong lý lịch, lấy điểm chung về học lực thì có thể phân nhóm thí sinh dựa theo tiêu chí học lực ghi trong kết quả tốt nghiệp...Vậy chúng ta phải lựa chọn tiêu chí nào làm điểm chung?

Hãy xem lại đề bài, chúng ta sẽ thấy câu : mỗi trường đều có mức điểm chuẩn khác nhau để đánh giá tiêu chí đạt hay không đạt của thí sinh

Như vậy, với riêng đề bài này, chúng ta có thể thấy, yếu tố trường có thể đưa ra làm điểm chung để có thể phân nhóm các thí sinh vì căn cứ vào yếu tố trường, chúng ta có thể xác định mức điểm chuẩn nhằm phân loại kết quả thí sinh và đây cũng là yêu cầu mà đề bài này đạt ra.

Theo đề bài, chúng ta có 100 trường, như vậy sẽ có 100 flyweight object khác nhau. Vậy thế nào là 1 flyweight object? Flyweight object được định nghĩa như sau:

Flyweight object là một đối tượng được chia sẻ có thể được sử dụng đồng thời trong nhiều ngữ cảnh (context). Flyweight object hoạt động như một đối tượng độc lập trong từng ngữ cảnh - nó không có khả năng phân biệt một thể hiện từ 1 đối tượng không được chia sẻ. Khái niệm chính của sự khác biệt này chính là trạng thái nội (intrinsic state) và trạng thái ngoại (extrinsic state) của flyweight object. Trạng thái nội lưu trữ những thông tin tin trong flyweight object, nó giúp cho flyweight object độc lập được với ngữ cảnh và giúp flyweight object có thể được chia sẻ. Trạng thái ngoại phụ thuộc và thay đổi theo ngữ cảnh do đó nó không thể được chia sẻ. Người dùng có thể truyền trạng thái ngoại vào flyweight object khi cần sử dụng.

Theo cách phân tích ở trên, thì trạng thái nội trong đề bài chính là yếu tố trường, còn trạng thái ngoại chính là các yếu tố còn lại như mã số thí sinh, điểm số...Yếu trường chính là yếu tố giúp cho flyweight object có thể được chia sẻ còn các yếu tố còn lại thì tùy vào ngữ cảnh, là đặc tính riêng biệt của từng flyweight object trong các ngữ cảnh riêng của nó, do đó nó thuộc về trạng thái ngoại.

Chúng ta xem xét mô hình để hiểu rõ hơn về mối quan hệ giữa các yếu tố hình thành nên Flyweight pattern.

4. Mô hình




5. Code sample


public interface StudentFlyweight {
    public void getResult(String studentID, float mark1, float mark2, float mark3);
}

public enum UniversityEnum {
    PLY,
    ECO,
    SPO
}

public class StudentFlyweightFactory {

    private final static StudentFlyweightFactory factory = new StudentFlyweightFactory();
    private Map<UniversityEnum, StudentFlyweight> studentMap = new HashMap<UniversityEnum, StudentFlyweight>();

    public static StudentFlyweightFactory getInstance() {
        return factory;
    }

    public synchronized StudentFlyweight getStudentFlyweight(UniversityEnum university) {

        StudentFlyweight student = studentMap.get(university);
        if (student != null) {
            return student;
        } else {
            StudentFlyweight s = null;
            switch (university) {
                case PLY:
                    s = new PLUniversity();
                    break;
                case ECO:
                    s = new EcoUniversity();
                    break;
                case SPO:
                    s = new SPUniversity();
                    break;
            }
            studentMap.put(university, s);
            return s;        
        }
        
    }
}

public class PLUniversity implements StudentFlyweight{
    private float standard_mark = 25;
    private String name = "Polytechnique University";

    @Override
    public void getResult(String studentID, float mark1, float mark2, float mark3) {
        float total = mark1 + mark2 + mark3;
        if (total < standard_mark){
            System.out.println(studentID + "(" + mark1 + "," + mark2 + ","+ mark3 + ")"+" failed the "+name +" exam");
        }else{
            System.out.println(studentID + "(" + mark1 + "," + mark2 + ","+ mark3 + ")"+" passed the "+name +" exam");
        }
    }

}

public class EcoUniversity implements StudentFlyweight {
    private float standard_mark = 18;
    private String name = "Economic University";

    @Override
    public void getResult(String studentID, float mark1, float mark2, float mark3) {
        float total = mark1 + mark2 + mark3;
        if (total < standard_mark){
            System.out.println(studentID + "(" + mark1 + "," + mark2 + ","+ mark3 + ")"+" failed the "+name +" exam");
        }else{
            System.out.println(studentID + "(" + mark1 + "," + mark2 + ","+ mark3 + ")"+" passed the "+name +" exam");
        }
    }
}

public class SPUniversity implements StudentFlyweight{
    private float standard_mark = 24;
    private String name = "Sport University";

    @Override
    public void getResult(String studentID, float mark1, float mark2, float mark3) {
        float total = mark1 * 2  + mark2 + mark3;
        if (total < standard_mark){
            System.out.println(studentID + "(" + mark1 + "," + mark2 + ","+ mark3 + ")"+" failed the "+name +" exam");
        }else{
            System.out.println(studentID + "(" + mark1 + "," + mark2 + ","+ mark3 + ")"+" passed the "+name +" exam");
        }
    }
}

public class FlyweightPattern {

    public static void main(String[] args) {
        UniversityEnum[] unilist = UniversityEnum.values();
        int totalstudent = 100;
        int index = 0;

        StudentFlyweightFactory factory = StudentFlyweightFactory.getInstance();
        FlyweightPattern pattern = new FlyweightPattern();
        for (int i = 1; i <= totalstudent; i++) {
            StudentFlyweight student = factory.getStudentFlyweight(unilist[index]);
            student.getResult(String.valueOf("ID_" + i), pattern.getRandom(0, 10), pattern.getRandom(0, 10), pattern.getRandom(0, 10));
            index++;
            if (index == 3) {
                index = 0;
            }
        }

    }

    private int getRandom(int min, int max) {
        return min + (int) (Math.random() * ((max - min) + 1));
    }
}



6. Mối liên hệ với các pattern khác


1 nhận xét: