Facade Pattern - mẫu thiết kế giao diện chung  
 

(Post 07/04/2006) Facade1 Pattern là pattern cung cấp một giao diện chung đơn giản thay cho một nhóm các giao diện có trong một hệ thống con (subsystem2). Façade Pattern định nghĩa một giao diện ở một cấp độ cao hơn để giúp cho người dùng có thể dễ dàng sử dụng hệ thống con này vì chỉ cần giao tiếp với một giao diện chung duy nhất.

Facade Pattern: “Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.” [GoF]

1. Định nghĩa

Facade1 Pattern là pattern cung cấp một giao diện chung đơn giản thay cho một nhóm các giao diện có trong một hệ thống con (subsystem2). Façade Pattern định nghĩa một giao diện ở một cấp độ cao hơn để giúp cho người dùng có thể dễ dàng sử dụng hệ thống con này vì chỉ cần giao tiếp với một giao diện chung duy nhất.

Façade Pattern cho phép các đối tượng truy cập vào hệ thống con bằng cách sử dụng giao diện chung này để giao tiếp với các giao diện có trong hệ thống con. Mục tiêu là che giấu các hoạt động trong hệ thống con.

Pattern này có thể được biểu thị như sau:

JDBC trong Java là một ví dụ tốt cho Façade Pattern.

2. Lợi ích

Việc sử dụng Façade Pattern đem lại các lợi ích sau:

  • Người dùng không cần biết đến sự phức tạp bên trong hệ thống con mà dễ dàng sử dụng hệ thống con vì chỉ giao tiếp với hệ thống con thông qua một giao diện chung đơn giản3 .
  • Chú ý là Façade Pattern không “đóng gói” (encapsulation) hệ thống con theo nghĩa hạn chế truy xuất; nó cung cấp một giao diện đơn giản trong lúc vẫn bộc lộ đầy đủ các chức năng của hệ thống con. Những người dùng cao cấp vẫn có thể truy xuất vào sâu bên trong hệ thống con khi cần thiết (sửa chữa nâng cấp hệ thống con).
  • Nâng cao khả năng độc lập của hệ thống con do cho phép nâng cấp đơn thể trong hệ thống con mà không cần phải sửa lại mã lệnh từ phía người dùng.
  • Giúp phân lớp (layer) hệ thống con và sự phụ thuộc của các đối tượng trong hệ thống con.

3. Trường hợp sử dụng

Người lập trình có thể dùng Façade Pattern trong những trường hợp sau:

  • Khi việc thiết kế các pattern sinh ra rất nhiều lớp làm người sử dụng rất khó để có thể hiểu được quy trình xử lý của chương trình. Và khi có rất nhiều hệ thống con mà mỗi hệ thống con đó lại có những giao diện riêng lẻ của nó nên rất khó cho việc sử dụng phối hợp.
  • Khi người lập trình muốn đưa ra một giao diện đơn giản cho người sử dụng một hệ thống phức tạp.
  • Khi người sử dụng phụ thuộc nhiều vào các lớp cài đặt. Việc áp dụng Façade Pattern sẽ tách biệt hệ thống con của người dùng và các hệ thống con khác, do đó tăng khả năng độc lập và khả chuyển của hệ thống con, dễ chuyển đổi nâng cấp trong tương lai.
  • Khi người lập trình muốn phân lớp các hệ thống con. Dùng Façade Pattern để định nghĩa cổng giao tiếp chung cho mỗi hệ thống con, do đó giúp đơn giản hóa sự phụ thuộc của các hệ thống con vì các hệ thống này chỉ giao tiếp với nhau thông qua các cổng giao diện chung đó.

4. Cách thực hiện

Các thành phần tham gia Façade Pattern:

  • Facade: biết rõ lớp của hệ thống con nào đảm nhận việc đáp ứng yêu cầu của client, sẽ chuyển yêu cầu của client đến các đối tượng của hệ thống con tương ứng.
  • Các lớp Subsystem: cài đặt các chức năng của hệ thống con, xử lý công việc được Facade. Các lớp này không cần biết Facade và không tham chiếu đến nó.

5. Các pattern liên quan

  • Abstract Factory: thường dùng để tạo giao diện cho một hệ thống con một cách độc lập, có thể dùng như một Façade.
  • Singleton: đối tượng Façade thường là một Singleton vì chỉ cần một đối tượng Façade.
  • Mediator: tương tự như Façade, nhưng Façade không định nghĩa chức năng mới cho hệ thống con, lớp Façade cũng không được các lớp của hệ thống con biết đến.

6. Ví dụ minh họa

Ví dụ minh họa hoạt động cộng tác phức tạp trong hệ thống con institute.aptech khi đăng ký một Student:

  • Các CourseStudent cần đăng ký trước trong Campus.
  • Sau đó Team được tạo ra gắn liền với một Course có trong Campus.
  • Cuối cùng là việc đăng ký (enroll) một số Student có trong Campus vào Team. Danh sách Student có trong Team có thể được hiển thị (display) ra.

Quy trình đăng ký phức tạp này được Facade thực hiện và Client chỉ cần gọi enroll() qua giao diện đơn giản của Facade. Việc thu thập thông tin về Team (tên Course, danh sách Student, …) cũng được Facade thực hiện. Kết quả được trả về với dạng đơn giản (tập hợp các chuỗi) để dễ dàng dùng trong GUI hoặc console; Client chỉ cần gọi display() thông qua giao diện đơn giản của Facade để nhận thông tin này.

a) Java

package institute.aptech;

class Student { private int code; private String name; public Student( int code, String name ) { this.code = code; this.name = name; }

public int getCode() { return code; } public String getName() { return name; } }

package institute.aptech;

class Course {
  private int code;
  private String name;

  public Course( int code, String name ) {
    this.code = code;
    this.name = name;
  }
	
  public int getCode() { return code; }	
  public String getName() { return name; }
}

import java.util.LinkedList;

class Team {
  private String name;
  private LinkedList students = new LinkedList();
  private Course course;
	
  public Team( String name ) { 
    this.name = name; 
  }
	
  public String getName() { return name; }
  public void setCourse( Course c ) {
    course = c; 
  }
  public Course getCourse() {
    return course;
  }

  public void addStudent( Student s ) {
    students.add( s );
  }
  public LinkedList getStudents() {
    return students;
  }
}

package institute.aptech;

import java.util.HashMap;

class Campus {
  private static HashMap students =new HashMap();
  private static HashMap courses =new HashMap();
	
  public Campus() {}
  public static void setStudent( int sCode
          , String sName ) {
    students.put( new Integer( sCode )
      , new Student( sCode, sName ) );
  }
	
  public static Student getStudent( int sCode ){
    return ( Student )students.get(
      new Integer( sCode ) );
  }
	
  public static void setCourse( int cCode
        , String cName ) {
    courses.put( new Integer( cCode )
      , new Course( cCode, cName ) );
  }
	
  public static Course getCourse( int cCode ){
    return ( Course )courses.get(
      new Integer( cCode ) );
  }
}

package institute.aptech;
import java.util.*;

public class Facade {
  private static HashMap teams = new HashMap();
	
  public static void buildCampus() {
    Campus.setCourse( 1000, "Operating System" );
    Campus.setCourse( 2000, "Core Java" );
    Campus.setStudent( 100, "Bill Gates" );
    Campus.setStudent( 101, "James Gosling" );
    Campus.setStudent( 102, "Linus Tovarld" );
  }
	
  public static void buildTeam( String tName
      , int courseCode ) {
    Team aTeam = new Team( tName );
    aTeam.setCourse(Campus.getCourse(courseCode));
    teams.put( tName, aTeam );
  }
	
  public void enroll(int studentCode
        , String tName){
    Student regStudent = 
      Campus.getStudent( studentCode );
    Team aTeam = ( Team )teams.get( tName );
    aTeam.addStudent( regStudent );
  }
	
  public Collection display( String tName ) {
    Vector result = new Vector();
    Team aTeam = ( Team )teams.get( tName );
		
    result.addElement( aTeam.getName() );
    result.addElement( aTeam.getCourse()
      .getName() );
    LinkedList students = aTeam.getStudents();
    for ( int i = 0; i < students.size(); ++i ) {
      result.addElement(((Student)students.get(i))
          .getName());
    }
    return result;
  }
}

package clients;
import institute.aptech.Facade;

import java.util.*;

public class FacadeClient {
  public static void main( String[] args ) {
    Facade facade = new Facade();

    Facade.buildCampus();
    Facade.buildTeam( "OS1000", 1000 );
    Facade.buildTeam( "CJ2000", 2000 );
		
    facade.enroll( 100, "OS1000" );
    facade.enroll( 101, "CJ2000" );
    facade.enroll( 102, "OS1000" );
		
    Collection c = facade.display( "OS1000" );
    Iterator iter = c.iterator();
    System.out.println( "Team Name: "
      + ( String )iter.next() );
    System.out.println( "Course Name: "
      + ( String )iter.next() );
    System.out.println( "Students List: " );
    while ( iter.hasNext() ) {
      System.out.println( "  + "
        + (  String )iter.next() );
    }
  }
}

b) C++

#include 
#include 
#include 
#include 

using namespace std;

namespace institute {
  namespace aptech { 
    class Student {
      int code;
      string name;
    public:
      Student( int c, string n ) : code ( c )
        , name( n ) { }
      string getName() const { return name; }
      int getCode() const { return code; }
    };

    class Course {
      int code;
      string name;
    public:
      Course() {}
      Course( int c, string n ) : code ( c )
        , name( n ) { }
      string getName() const { return name; }
      int getCode() const { return code; }
    };

    class Team {
      string name;
      list students;
      Course* course;
    public:
      Team( string n ) : name( n ) { }
      string getName() { return name; }
      void addStudent( Student* s ) {
        students.push_back( s ); }
      void setCourse( Course* c ) { course = c; }
      const Course* getCourse() const {
        return course; }
      const list getStudents() const {
        return students; }
    };

    class Campus {
      static map students;
      static map courses;
    public:
      Campus() {}
      static void setStudent( int sCode
            , string sName ) {
        students[sCode] =
          new Student( sCode, sName );
      }

      static void setCourse( int cCode
          , string cName ) {
        courses[cCode] =
          new Course( cCode, cName );
      }

      static Student* getStudent( int sCode ) {
        return students[sCode]; }
      static Course* getCourse( int cCode ) {
        return courses[cCode]; }
    };
    map Campus::students;
    map Campus::courses;

    class Facade {
      static map teams;
    public:
      static void buildCampus() {
        Campus::setCourse( 1000,
          "Operating System" );
        Campus::setCourse( 2000, "Core Java" );
        Campus::setStudent( 100, "Bill Gates" );
        Campus::setStudent(101, "James Gosling");
        Campus::setStudent(102, "Linus Tovarld");
      }
      
      static void buildTeam( string tName
             , int courseCode ) {
        Team* aTeam = new Team( tName );
        aTeam->setCourse( Campus::getCourse(
            courseCode ) );
        teams[tName] = aTeam;
      }
      
      void enroll(int studentCode, string tName){
        Student* regStudent
          = Campus::getStudent( studentCode );
        Team* aTeam = teams[tName];
        aTeam->addStudent( regStudent );
      }
      
      list display( string tName ) {
        Team* aTeam = teams[tName];
        list result;
        result.push_back( aTeam->getName() );
        result.push_back( aTeam->getCourse()
            ->getName() );
        list students = aTeam
            ->getStudents();
        list::const_iterator it
          = students.begin();
        while ( it != students.end() ) {
          result.push_back( (*it++)->getName() );
        }
        return result;
      }
    };
    map Facade::teams;
  }
}

using namespace institute::aptech;
int main() {
  Facade facade;

  Facade::buildCampus();
  Facade::buildTeam( "OS1000", 1000 );
  Facade::buildTeam( "CJ2000", 2000 );
    
  facade.enroll( 100, "OS1000" );
  facade.enroll( 101, "CJ2000" );
  facade.enroll( 102, "OS1000" );

  list result = facade.display( "OS1000" );
  list::const_iterator it = result.begin();
  cout << "Team Name: " << *it++ << "\n";
  cout << "Course Name: " << *it++ << "\n";
  cout << "Students List: " << "\n";
  while ( it != result.end() ) {
    cout << "  + " + *it++ << "\n";
  }
  return 0;
}

c) C#

using System;
using System.Collections;

namespace institute.aptech 
{
  class Student 
  {
    private int code;
    private string name;
    public int Code { get { return code; }   }
    public string Name { get { return name; } }
    
    public Student( int code, string name ) 
    {
      this.code = code;
      this.name = name;
    }
  }

  class Course 
  {
    private int code;
    private string name;
    public int Code { get { return code; }   }
    public string Name { get { return name; } }

    public Course( int code, string name ) 
    {
      this.code = code;
      this.name = name;
    }
  }

  class Team 
  {
    private string name;
    private Course course;
    private ArrayList students = 
      new ArrayList();
    public string Name 
    {
      get { return name; } 
    }
    public Course Course
    {
      get { return course; }
      set { course = value; }
    }
  
    public Student this [int index]
    {
      get 
      { 
        return ( (Student)students[index] );  
      }
      set { students[index] = value; }
    }

    public int Count 
    {
      get { return students.Count; } 
    }
    
    public Team( string name ) 
    {
      this.name = name;
    }

    public void AddStudent( Student s )
    { 
      students.Add( s ); 
    }
  }

  class Campus 
  {
    private static Hashtable students =
      new Hashtable();
    private static Hashtable courses =
      new Hashtable();

    public Campus() {}
    public static void SetStudent(
      int sCode, string sName ) 
    {
      students.Add( sCode, new Student
        ( sCode, sName ) );
    }

    public static Student GetStudent(int sCode)
    {
      return ( Student )students[sCode];
    }

    public static void SetCourse( int cCode
      , string cName ) 
    {
      courses.Add( cCode, new Course( cCode
        , cName ) );
    }
  
    public static Course GetCourse(int cCode) 
    {
      return ( Course )courses[cCode];
    }
  }

  public class Facade 
  {
    private static Hashtable teams =
      new Hashtable();
  
    public static void BuildCampus() 
    {
      Campus.SetCourse(1000, "Operating System");
      Campus.SetCourse( 2000, "Core Java" );
      Campus.SetStudent( 100, "Bill Gates" );
      Campus.SetStudent( 101, "James Gosling" );
      Campus.SetStudent( 102, "Linus Tovarld" );
    }
  
    public static void BuildTeam( string tName
        , int courseCode ) 
    {
      Team aTeam = new Team( tName );
      aTeam.Course = Campus.GetCourse(
        courseCode );
      teams.Add( tName, aTeam );
    }
  
    public void Enroll( int studentCode
        , string tName ) 
    {
      Student regStudent = 
        Campus.GetStudent( studentCode );
      Team aTeam = ( Team )teams[tName];
      aTeam.AddStudent( regStudent );
    }

    public ICollection Display( String tName ) 
    {
      ArrayList result = new ArrayList();
      Team aTeam = ( Team )teams[tName];
    
      result.Add( aTeam.Name );
      result.Add( aTeam.Course.Name );
      for ( int i = 0; i < aTeam.Count; ++i )
      {
        result.Add( aTeam[i].Name );
      }
      return result;
    }
  }
}

namespace clients 
{
  using institute.aptech;
  public class FacadeClient 
  {
    public static void Main() 
    {
      Facade facade = new Facade();

      Facade.BuildCampus();
      Facade.BuildTeam( "OS1000", 1000 );
      Facade.BuildTeam( "CJ2000", 2000 );
    
      facade.Enroll( 100, "OS1000" );
      facade.Enroll( 101, "CJ2000" );
      facade.Enroll( 102, "OS1000" );
    
      ICollection c = facade.Display( "OS1000" );
      IEnumerator iter = c.GetEnumerator();
      
      iter.MoveNext();
      Console.Out.WriteLine( "Team Name: "
        + ( string )iter.Current );
      iter.MoveNext();
      Console.Out.WriteLine( "Course Name: "
        + ( string )iter.Current );
      Console.Out.WriteLine( "Students List: " );
      while ( iter.MoveNext() ) 
        Console.Out.WriteLine( "  + "
          + (  String )iter.Current );
    }
  }
}

Dương Thiên Tứ - Faculty FPT-Aptech

Chú thích

1 Façade: mặt tiền
2 Subsystem là nhóm các lớp, hoặc nhóm các lớp với các subsystem khác; chúng cộng tác với nhau để thực hiện một số tác vụ.
3 Mỗi hệ thống con có thể có nhiều giao diện Façade.


 
 

 
     
 
Công nghệ khác:


Chữ ký điện tử: Đảm bảo an toàn dữ liệu truyền trên mạngGrid Computing - Part 2
Singleton Pattern - mẫu thiết kế đơn nhấtAdapter Pattern (mẫu thiết kế tiếp hợp)
AJAX - sự kết hợp kỳ diệu của công nghệ webSOA: Ngôi sao mới trong lĩnh vực phần mềm
  Xem tiếp    
 
Lịch khai giảng của hệ thống
 
Ngày
Giờ
T.Tâm
TP Hồ Chí Minh
Hà Nội
 
   
New ADSE - Nhấn vào để xem chi tiết
Mừng Sinh Nhật Lần Thứ 20 FPT-APTECH
Nhấn vào để xem chi tiết
Bảng Vàng Thành Tích Sinh Viên FPT APTECH - Nhấn vào để xem chi tiết
Cập nhật công nghệ miễn phí cho tất cả cựu sinh viên APTECH toàn quốc
Tiết Thực Vì Cộng Đồng
Hội Thảo CNTT
Những khoảnh khắc không phai của Thầy Trò FPT-APTECH Ngày 20-11