+6

Design patterns - Facade Pattern

1. Intent

  • Cung cấp một giao diện thống nhất cho một tập hợp các giao diện trong một hệ thống con. Facade định nghĩa một giao diện cấp cao hơn làm cho hệ thống con dễ sử dụng hơn.
  • Bao bọc một hệ thống con phức tạp với một giao diện đơn giản.

2. Example

  • Người tiêu dùng bắt gặp mô hình Facade khi đặt hàng từ một cửa hàng. Người tiêu dùng gọi điện thoại và nói chuyện với một đại diện dịch vụ khách hàng. Đại diện dịch vụ khách hàng hoạt động như Facade, cung cấp giao diện cho bộ phận hoàn thành đơn đặt hàng, bộ phận thanh toán và bộ phận vận chuyển.

3. Motivation

  • Cấu trúc một hệ thống vào các hệ thống con giúp giảm sự phức tạp. Mục tiêu thiết kế chung là giảm thiểu sự liên lạc và phụ thuộc giữa các hệ thống con. Một cách để đạt được mục tiêu này là giới thiệu một đối tượng Facade cung cấp một giao diện đơn giản đến các cơ sở chung của một hệ thống con.

  • Ví dụ : một môi trường lập trình cho phép các ứng dụng truy cập đến hệ thống con trình biên dịch của nó. Hệ thống con này chứa các lớp như Scanner, Parser, ProgramNode, BytecodeStream, và ProgramNodeBuilder để thực hiện trình biên dịch.

  • Một số ứng dụng chuyên biệt có thể cần truy cập trực tiếp các lớp này. Nhưng hầu hết các “khách hàng” của trình biên dịch nói chung không quan tâm đến các chi tiết như phân tích cú pháp và tạo mã;

  • Họ chỉ đơn thuần muốn biên dịch một số mã. Đối với họ, các giao diện mạnh mẽ nhưng cấp thấp trong hệ thống con trình biên dịch chỉ làm phức tạp nhiệm vụ của họ.

  • Để cung cấp một giao diện cấp cao hơn có thể bao bọc các lớp con trước các truy cập từ các máy khách, trình biên dịch của hệ thống con cũng bao gồm một lớp Complier. Lớp này định nghĩa một giao diện thống nhất với chức năng của trình biên dịch. Lớp Compiler hoạt động như một Facade:

  • Nó cung cấp cho khách hàng một giao diện duy nhất, đơn giản đến trình biên dịch của hệ thống con. Nó kết nối các lớp thực hiện chức năng trình biên dịch mà không che giấu chúng hoàn toàn. Mặt tiền của trình biên dịch làm cho công việc dễ dàng hơn đối với hầu hết các lập trình viên mà không che giấu các chức năng cấp thấp trừ một vài cái cần thiết.

4. Applicability

  • Sử dụng mẫu Facade khi :
  1. Bạn muốn cung cấp một giao diện đơn giản cho một hệ thống con phức tạp. Các hệ thống con thường trở nên phức tạp hơn khi chúng phát triển. Hầu hết các mô hình khi được áp dụng, kết quả trong các lớp nhiều hơn và nhỏ hơn. Điều này làm cho hệ thống con trở nên dễ sử dụng hơn và dễ tùy chỉnh hơn nhưng cũng trở nên khó sử dụng hơn cho khách hàng mà không cần thiết phải tùy chỉnh nó. Facade có thể cung cấp một chế độ xem mặc định đơn giản của hệ thống phụ đủ tốt cho hầu hết các khách hàng. Chỉ những khách hàng cần nhiều tính tùy chỉnh mới cần vượt qua facade.

  2. Có nhiều phụ thuộc giữa khách hàng và các lớp thực hiện của một lớp trừu tượng. Giới thiệu một Facade để tách riêng hệ thống con từ khách hàng và các hệ thống con khác, do đó thúc đẩy sự độc lập của hệ thống con và tính di động.

  3. Bạn muốn bao bọc, che giấu tính phức tạp trong các hệ thống con của bạn. Sử dụng Facade để xác định điểm vào cho mỗi cấp độ hệ thống con. Nếu các hệ thống con phụ thuộc, sau đó bạn có thể đơn giản hóa các mối quan hệ phụ thuộc giữa chúng bằng cách làm cho chúng giao tiếp với nhau thông qua mặt tiền của chúng.

5. Structure

6. Participants

  1. Facade (vd: rình biên dịch)
    • Biết được các lớp con của hệ thống con nào chịu trách nhiệm về một yêu cầu.
    • Ủy thác các yêu cầu của khách hàng tới các đối tượng của hệ thống con thích hợp.
  2. Các lớp hệ thống con (vd: Máy quét, Trình phân tích cú pháp, ProgramNode, v.v ...)
    • Thực hiện các chức năng hệ thống con.
    • Xử lý công việc được chỉ định bởi đối tượng Facade.
    • Không nhận biết được facade, vì thế chúng không lưu trữ lại dữ liệu liên quan nào về nó.

7. Collaborations

  • Khách hàng giao tiếp với hệ thống con bằng cách gửi yêu cầu tới Facade, facade sẽ chuyển tiếp chúng tới các đối tượng trong hệ thống con thích hợp. Mặc dù chỉ có các đối tượng trong hệ thống con thực hiện công việc thực tế, facade có thể phải làm công việc riêng của mình để dịch giao diện của nó đến các giao diện hệ thống con.
  • Khách hàng sử dụng mặt tiền không phải truy cập trực tiếp đến các đối tượng hệ thống con.

8. Consequences

Mẫu mặt tiền cung cấp những lợi ích sau:

  1. Facade nhận các yêu cầu từ khách hàng và gửi yêu cầu đó đến hệ thống con phù hợp để xử lý, do đó làm giảm số lượng các đối tượng mà khách hàng giao dịch và làm cho hệ thống con dễ sử dụng hơn.

  2. Nó khuyến khích mối liên kết yếu giữa hệ thống phụ và khách hàng. Thường thì các thành phần trong một hệ thống con được kết hợp chặt chẽ. Khớp nối yếu cho phép bạn thay đổi các thành phần của hệ thống phụ mà không ảnh hưởng đến khách hàng. Facade có thể loại bỏ sự phức tạp hoặc phụ thuộc lẫn nhau giữa các đối tượng theo kiểu vòng tròn. Đây có thể là một thành quả quan trọng khi khách hàng và hệ thống con được thực hiện độc lập. Giảm sự phụ thuộc biên dịch là rất quan trọng trong các hệ thống phần mềm lớn. Bạn muốn tiết kiệm thời gian bằng cách giảm thiểu biên dịch lại khi các lớp hệ thống con thay đổi. Giảm sự phụ thuộc biên dịch với facade có thể giới hạn việc biên dịch lại cần thiết cho một sự thay đổi nhỏ trong một hệ thống con quan trọng. Facade cũng có thể đơn giản hóa quá trình kết nối tới platform khác, bởi vì thông thường không bắt buộc phải xây dựng toàn bộ hệ thống trong khi xây dựng 1 hệ thống con.

  3. Nó không ngăn chặn các ứng dụng sử dụng các lớp con của hệ thống con nếu cần đến. Vì vậy, bạn có thể lựa chọn giữa dễ sử dụng và tính tổng quát.

9. Sample Code

/* Complex parts */

class CPU {
    public void freeze() { ... }
    public void jump(long position) { ... }
    public void execute() { ... }
}

class HardDrive {
    public byte[] read(long lba, int size) { ... }
}

class Memory {
    public void load(long position, byte[] data) { ... }
}

/* Facade */

class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDrive hd;

    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDrive();
    }

    public void start() {
        processor.freeze();
        ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
        processor.jump(BOOT_ADDRESS);
        processor.execute();
    }
}

/* Client */

class You {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

10. Discuss

Problem

  • Một vấn đề phổ biến mà các đội phát triển phần mềm gặp phải khi sử dụng mô hình Facade xảy ra khi lớp Façade được sử dụng để đại diện cho toàn bộ hệ thống mà nhóm đang làm việc. Một nhóm từ 20 đến 30 người gửi mọi phương thức gọi đến hệ thống thông qua Façade, với mỗi thành viên trong nhóm thực hiện một số thay đổi cho hệ thống mỗi ngày.

  • Do sự lệ thuộc nặng nề vào lớp Façade, tuy nhiên, lịch trình của đội thường bị trì hoãn bởi vì lớp Façade thường bị "khóa" bởi một nhà phát triển cụ thể trong một thời gian. Thảo luận làm thế nào vấn đề này có thể được khắc phục mà không phải hy sinh việc sử dụng các mẫu Facade.

Solution

  • Nếu bạn thiết kế một hệ thống mà từ 20-30 người phải chỉnh sửa cùng một lớp codebase của bạn trên cơ sở hàng ngày, tôi sẽ nói rằng bạn sẽ có một vấn đề tổ chức khá lớn và một vấn đề kiến trúc khá lớn với hệ thống của bạn.

  • Để giải quyết những vấn đề này, tôi sẽ bắt đầu chia tách các nhóm với kích thước nhỏ hơn, với tối đa 5 đến 6 nhà phát triển mỗi đội, và mỗi đội chỉ chịu trách nhiệm về một phần của cơ sở mã. Giả sử mỗi nhóm quản lý một số thành phần, với các giao diện được xác định rõ ràng giữa các thành phần, "mặt tiền" của bạn sẽ nằm trong một trong những thành phần đó, do đó bạn thực sự đã giảm số lượng người có thể có xung đột xuống 5-6.

  • Nếu 5 đến 6 người vẫn phải chỉnh sửa lớp mỗi ngày, thì vẫn còn có điều gì đó sai trái với trách nhiệm của lớp đó. Giải pháp để giải quyết vấn đề đó là chính xác những gì Robert Harvey đã viết trong các nhận xét: chia lớp thành các lớp con nhỏ hơn.

  • Lưu ý rằng chỉ cần sử dụng một lớp học phát triển bởi nhiều người, mà trong số họ không ai quản lý nó, đó là vô lý . Chỉ việc chỉnh sửa một lớp đồng thời bởi hai người có thể dẫn đến xung đột (conflict code), điều này có thể được giải quyết bằng sự trợ giúp của bất kỳ hệ thống kiểm soát phiên bản nào.

11. Related Patterns

  • Abstract Factory có thể được sử dụng với Facade để cung cấp một giao diện cho việc tạo ra các đối tượng hệ thống con theo cách độc lập của hệ thống con. Abstract Factory cũng có thể được sử dụng như là một sự thay thế cho Facade để ẩn các lớp nền cụ thể.

  • Facade định nghĩa một giao diện mới, trong khi Adapter sử dụng một giao diện cũ. Hãy nhớ rằng Adapter làm cho hai giao diện hiện tại hoạt động với nhau như là trái ngược với việc xác định một giao diện hoàn toàn mới.

  • Trong khi Flyweight cho thấy làm thế nào để tạo ra rất nhiều các đối tượng nhỏ, Facade cho thấy làm thế nào để tạo một đối tượng đại diện cho một toàn bộ hệ thống con.

  • Mediator tương tự như Facade trong đó nó tóm tắt các chức năng của các lớp học hiện có. Mediator abstracts tập trung các thông tin tùy tiện giữa các đối tượng tương đồng. Nó thường xuyên "thêm các giá trị", mà nó được biết , được tham chiếu bởi các đối tượng tương đồng. Ngược lại, Facade định nghĩa một giao diện đơn giản hơn cho một hệ thống con, nó không thêm các chức năng mới, và các lớp hệ thống con không biết.

  • Các đối tượng Facade thường là Singletons bởi vì chỉ cần duy nhất một đối tượng Facade.

  • Adapter và mặt tiền đều là các mô hình "bao bọc" lấy các lớp, các đối tượng nhưng chúng là các mô hình "bao bọc" khác nhau. Mục đích của Facade là tạo ra một giao diện đơn giản hơn, và mục đích của Adapter là mở rộng cho một giao diện hiện có. Trong khi Facade thường kết hợp nhiều đối tượng thì Adapter kết hợp với một đối tượng duy nhất; Facade có thể bao gồm một số đối tượng phức tạp đơn lẻ và Adapter có thể bao gồm một vài đối tượng kế thừa.

  • Câu hỏi: Vì vậy, cách để cho biết sự khác biệt giữa các mô hình Adapter và mô hình Facade là Adapter bao gồm một lớp học và Facade có thể đại diện cho nhiều lớp học?

  • Trả lời: Không! Hãy nhớ rằng, mẫu Adapter thay đổi giao diện của một hoặc nhiều lớp thành một giao diện mà khách hàng mong đợi. Trong khi hầu hết các ví dụ cho thấy Adapter thích ứng với một lớp, bạn có thể cần phải thích ứng nhiều lớp để cung cấp giao diện cho một khách hàng. Tương tự như vậy, Facade có thể cung cấp một giao diện đơn giản cho một lớp duy nhất với một giao diện rất phức tạp. Sự khác biệt giữa hai mô hình không phải là về số lượng lớp mà chúng "bao gồm", đó mà mục đích của chúng.

12. Referenced documents

https://en.wikipedia.org/wiki/Facade_pattern https://softwareengineering.stackexchange.com/questions/277682/beginner-facade-pattern-example https://sourcemaking.com/design_patterns/facade Design Patterns: Elements of Reusable Object-Oriented Software by GoF


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí