๐Ÿ–with Modern Backend Development

Design Patterns for Modern Backend Development โ€“ with Example Use Cases

MVC (Model-View-Controller) Pattern

Overview

Mรด hรฌnh Model-View-Controller (MVC) lร  mแป™t mแบซu thiแบฟt kแบฟ ฤ‘ฦฐแปฃc sแปญ dแปฅng rแป™ng rรฃi trong phรกt triแปƒn backend hiแป‡n ฤ‘แบกi. Nรณ cung cแบฅp cรกch phรขn tรกch tแบงng trรฌnh bร y (View) khแปi tแบงng business logic vร  lฦฐu trแปฏ dแปฏ liแป‡u (Model vร  Controller). Sแปฑ phรขn tรกch nร y giรบp cรกc lแบญp trรฌnh viรชn viแบฟt mรฃ mรด-ฤ‘un hฦกn vร  dแป… dร ng bแบฃo trรฌ.

Trong mรด hรฌnh MVC, Model ฤ‘แบกi diแป‡n cho dแปฏ liแป‡u vร  business logic cแปงa แปฉng dแปฅng. Controller hoแบกt ฤ‘แป™ng nhฦฐ mแป™t trung gian giแปฏa Model vร  View, xแปญ lรฝ ฤ‘แบงu vร o tแปซ ngฦฐแปi dรนng vร  cแบญp nhแบญt Model tฦฐฦกng แปฉng. View chแป‹u trรกch nhiแป‡m trรฌnh bร y dแปฏ liแป‡u cho ngฦฐแปi dรนng vร  nhแบญn ฤ‘แบงu vร o tแปซ ngฦฐแปi dรนng.

Mแป™t trong cรกc ฦฐu ฤ‘iแปƒm chรญnh cแปงa viแป‡c sแปญ dแปฅng mรด hรฌnh MVC lร  cho phรฉp dแป… dร ng kiแปƒm tra vร  bแบฃo trรฌ mรฃ nguแป“n. Vรฌ Model vร  Controller ฤ‘ฦฐแปฃc tรกch ra khแปi View, nรชn cรณ thแปƒ kiแปƒm tra vร  sแปญa ฤ‘แป•i tแปซng thร nh phแบงn mแป™t cรกch ฤ‘แป™c lแบญp.

Lแปฃi รญch khรกc cแปงa viแป‡c sแปญ dแปฅng mรด hรฌnh MVC lร  cho phรฉp tรกi sแปญ dแปฅng mรฃ. Model vร  Controller cรณ thแปƒ ฤ‘ฦฐแปฃc tรกi sแปญ dแปฅng trong cรกc View khรกc nhau, cung cแบฅp mแป™t cรกch tiแบฟp cแบญn mรด-ฤ‘un hฦกn vแป›i phรกt triแปƒn phแบงn mแปm.

Nhรฌn chung, mรด hรฌnh MVC lร  mแป™t cรดng cแปฅ hแปฏu รญch ฤ‘แปƒ tแบกo ra cรกc hแป‡ thแป‘ng backend cรณ thแปƒ mแปŸ rแป™ng, dแป… bแบฃo trรฌ vร  hiแป‡u quแบฃ. Nรณ phรขn tรกch cรกc mแป‘i quan tรขm vร  cho phรฉp mแป™t cรกch tiแบฟp cแบญn mรด-ฤ‘un hฦกn trong phรกt triแปƒn phแบงn mแปm, giรบp dแป… dร ng kiแปƒm tra, bแบฃo trรฌ vร  sแปญa ฤ‘แป•i mรฃ nguแป“n.

Example of using the MVC pattern in a web application

ฤแบงu tiรชn, chรบng ta sแบฝ xem xรฉt mแป™t vรญ dแปฅ vแป viแป‡c sแปญ dแปฅng mรด hรฌnh MVC trong mแป™t แปฉng dแปฅng web vแป›i framework Node.js phแป• biแบฟn, Express.js.

Trong mแป™t แปฉng dแปฅng Express.js, thร nh phแบงn Model thฦฐแปng ฤ‘ฦฐแปฃc thแปฑc hiแป‡n bแบฑng cรกch sแปญ dแปฅng cฦก sแปŸ dแปฏ liแป‡u nhฦฐ MongoDB hoแบทc MySQL. Thร nh phแบงn View thฦฐแปng ฤ‘ฦฐแปฃc thแปฑc hiแป‡n bแบฑng cรกch sแปญ dแปฅng cรกc cรดng cแปฅ tแบกo mแบซu nhฦฐ EJS hoแบทc Handlebars. Thร nh phแบงn Controller ฤ‘ฦฐแปฃc thแปฑc hiแป‡n bแบฑng cรกch sแปญ dแปฅng cรกc hร m phแบงn mแปm trung gian (middleware), cรกc hร m ฤ‘ฦฐแปฃc thแปฑc thi theo mแป™t thแปฉ tแปฑ cแปฅ thแปƒ khi cรณ yรชu cแบงu gแปญi ฤ‘แบฟn mรกy chแปง.

Vรญ dแปฅ, khi ngฦฐแปi dรนng gแปญi yรชu cแบงu ฤ‘แปƒ xem mแป™t bร i ฤ‘ฤƒng trรชn blog, yรชu cแบงu ฤ‘ฦฐแปฃc xแปญ lรฝ bแปŸi thร nh phแบงn Controller. Controller lแบฅy bร i viแบฟt tแปซ thร nh phแบงn Model vร  truyแปn nรณ sang thร nh phแบงn View, nฦกi hiแปƒn thแป‹ nรณ bแบฑng cรกch sแปญ dแปฅng mแป™t cรดng cแปฅ tแบกo mแบซu. HTML kแบฟt quแบฃ sau ฤ‘รณ ฤ‘ฦฐแปฃc gแปญi trแบฃ lแบกi trรฌnh duyแป‡t cแปงa ngฦฐแปi dรนng.

Sแปญ dแปฅng mรด hรฌnh MVC trong mแป™t แปฉng dแปฅng web cรณ thแปƒ mang lแบกi nhiแปu lแปฃi รญch, bao gแป“m khแบฃ nฤƒng mแปŸ rแป™ng, bแบฃo trรฌ vร  kiแปƒm tra ฤ‘ฦฐแปฃc cแบฃi thiแป‡n. Bแบฑng cรกch tรกch แปฉng dแปฅng thร nh cรกc thร nh phแบงn riรชng biแป‡t, cรกc nhร  phรกt triแปƒn cรณ thแปƒ thay ฤ‘แป•i mแป™t thร nh phแบงn mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn cรกc thร nh phแบงn khรกc. ฤiแปu nร y giรบp dแป… dร ng bแบฃo trรฌ vร  kiแปƒm tra แปฉng dแปฅng theo thแปi gian.

Trong vรญ dแปฅ sau ฤ‘รขy, Model ฤ‘ฦฐแปฃc thแปƒ hiแป‡n bแปŸi lแป›p PostModel, cรณ trรกch nhiแป‡m lแบฅy vร  lฦฐu dแปฏ liแป‡u vร o cฦก sแปŸ dแปฏ liแป‡u.

View ฤ‘ฦฐแปฃc thแปƒ hiแป‡n bแปŸi lแป›p PostView, cรณ trรกch nhiแป‡m hiแปƒn thแป‹ trang HTML vร  xแปญ lรฝ ฤ‘แบงu vร o tแปซ ngฦฐแปi dรนng.

Controller ฤ‘ฦฐแปฃc thแปƒ hiแป‡n bแปŸi lแป›p PostController, hoแบกt ฤ‘แป™ng nhฦฐ mแป™t trung gian giแปฏa Model vร  View. Nรณ khแปŸi tแบกo View, xแปญ lรฝ ฤ‘แบงu vร o tแปซ ngฦฐแปi dรนng vร  cแบญp nhแบญt View dแปฑa trรชn cรกc thay ฤ‘แป•i cแปงa Model.

// the model
interface Post {
  id: number;
  title: string;
  content: string;
  date: Date;
}

class PostModel {
  private posts: Post[] = [];

  getPosts() {
    // fetch posts from database
    return this.posts;
  }

  addPost(post: Post) {
    // save post to database
    this.posts.push(post);
  }
}
// the view
class PostView {
  displayPosts(posts: Post[]) {
    // render posts to the HTML page
  }

  getPostFromInput(): Post {
    // retrieve input values from the HTML page
    // and create a new Post object
  }
}
// the controller
class PostController {
  private model: PostModel;
  private view: PostView;

  constructor(model: PostModel, view: PostView) {
    this.model = model;
    this.view = view;
  }

  init() {
    // initialize the view
    this.view.displayPosts(this.model.getPosts());
  }

  addPost() {
    // get new post from view
    const post = this.view.getPostFromInput();
    // add post to model
    this.model.addPost(post);
    // update view
    this.view.displayPosts(this.model.getPosts());
  }
}

Viแป‡c triแปƒn khai mแบซu MVC nร y cho phรฉp tรกch biแป‡t cรกc mแป‘i quan tรขm vร  tรญnh mรด ฤ‘un trong web application code, khiแบฟn viแป‡c bแบฃo trรฌ vร  mแปŸ rแป™ng dแป… dร ng hฦกn theo thแปi gian.

Repository Pattern

Overview

Mแบซu Repository lร  mแป™t mแบซu thiแบฟt kแบฟ cung cแบฅp mแป™t lแป›p trแปซu tฦฐแปฃng giแปฏa lแป›p truy cแบญp dแปฏ liแป‡u vร  phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng. Nรณ tรกch riรชng logic truy xuแบฅt dแปฏ liแป‡u tแปซ lแป›p lฦฐu trแปฏ dแปฏ liแป‡u, cung cแบฅp mแป™t phฦฐฦกng phรกp phรกt triแปƒn phแบงn mแปm mรด-ฤ‘un hฦกn.

Trong mแบซu Repository, mแป™t kho lฦฐu trแปฏ hoแบกt ฤ‘แป™ng nhฦฐ mแป™t ngฦฐแปi trung gian giแปฏa lแป›p lฦฐu trแปฏ dแปฏ liแป‡u vร  lแป›p logic แปฉng dแปฅng. Nรณ cung cแบฅp mแป™t ฤ‘iแปƒm nhแบญp duy nhแบฅt ฤ‘แปƒ truy xuแบฅt vร  thao tรกc dแปฏ liแป‡u, cho phรฉp phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng tรกch rแปi khแปi cรกc chi tiแบฟt cแปฅ thแปƒ cแปงa lแป›p lฦฐu trแปฏ dแปฏ liแป‡u. ฤiแปu nร y lร m cho viแป‡c thay ฤ‘แป•i lแป›p lฦฐu trแปฏ dแปฏ liแป‡u dแป… dร ng hฦกn mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng.

Mแป™t trong nhแปฏng lแปฃi thแบฟ chรญnh cแปงa viแป‡c sแปญ dแปฅng mแบซu Repository lร  nรณ cho phรฉp mแป™t phฦฐฦกng phรกp phรกt triแปƒn phแบงn mแปm mรด-ฤ‘un hฦกn. Lแป›p logic แปฉng dแปฅng ฤ‘ฦฐแปฃc tรกch ra khแปi lแป›p lฦฐu trแปฏ dแปฏ liแป‡u, lร m cho viแป‡c kiแปƒm tra vร  bแบฃo trรฌ tแปซng thร nh phแบงn riรชng lแบป dแป… dร ng hฦกn. ฤiแปu nร y cลฉng lร m cho viแป‡c tรกi sแปญ dแปฅng lแป›p logic แปฉng dแปฅng vแป›i cรกc lแป›p lฦฐu trแปฏ dแปฏ liแป‡u khรกc nhau trแปŸ nรชn dแป… dร ng hฦกn.

Mแป™t lแปฃi รญch khรกc cแปงa viแป‡c sแปญ dแปฅng mแบซu Repository lร  nรณ cรณ thแปƒ cแบฃi thiแป‡n hiแป‡u suแบฅt bแบฑng cรกch giแบฃm sแป‘ lฦฐแปฃng lแบงn gแปi ฤ‘แบฟn lแป›p lฦฐu trแปฏ dแปฏ liแป‡u. Do logic truy cแบญp dแปฏ liแป‡u ฤ‘ฦฐแปฃc ฤ‘รณng gรณi trong kho lฦฐu trแปฏ, nรชn cรณ thแปƒ tแป‘i ฦฐu hรณa truy vแบฅn vร  giแบฃm sแป‘ lฦฐแปฃng lแบงn gแปi cฦก sแปŸ dแปฏ liแป‡u.

Nhรฌn chung, mแบซu Repository lร  mแป™t cรดng cแปฅ hแปฏu รญch ฤ‘แปƒ tแบกo ra cรกc hแป‡ thแป‘ng phรญa sau linh hoแบกt, dแป… bแบฃo trรฌ vร  hiแป‡u quแบฃ. Nรณ tรกch biแป‡t cรกc mแป‘i quan tรขm vร  cho phรฉp mแป™t phฦฐฦกng phรกp phรกt triแปƒn phแบงn mแปm mรด-ฤ‘un hฦกn, giรบp viแป‡c kiแปƒm tra, bแบฃo trรฌ vร  sแปญa ฤ‘แป•i cฦก sแปŸ mรฃ dแป… dร ng hฦกn. Nรณ cลฉng cรณ thแปƒ cแบฃi thiแป‡n hiแป‡u suแบฅt bแบฑng cรกch giแบฃm sแป‘ lฦฐแปฃng lแบงn gแปi ฤ‘แบฟn lแป›p lฦฐu trแปฏ dแปฏ liแป‡u.

Example of using the Repository pattern with a database

Mแบซu Repository lร  mแป™t mแบซu thiแบฟt kแบฟ cung cแบฅp mแป™t lแป›p trแปซu tฦฐแปฃng giแปฏa lแป›p truy cแบญp dแปฏ liแป‡u vร  phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng. Trong mแบซu Repository, cฦก sแปŸ dแปฏ liแป‡u ฤ‘ฦฐแปฃc biแปƒu diแป…n dฦฐแป›i dแบกng mแป™t tแบญp hแปฃp cรกc ฤ‘แป‘i tฦฐแปฃng, vแป›i mแป—i ฤ‘แป‘i tฦฐแปฃng ฤ‘แบกi diแป‡n cho mแป™t bแบฃng hoแบทc bแป™ sฦฐu tแบญp trong cฦก sแปŸ dแปฏ liแป‡u. Lแป›p Repository cung cแบฅp mแป™t tแบญp hแปฃp cรกc phฦฐฦกng thแปฉc ฤ‘แปƒ tฦฐฦกng tรกc vแป›i cฦก sแปŸ dแปฏ liแป‡u, chแบณng hแบกn nhฦฐ tแบกo, ฤ‘แปc, cแบญp nhแบญt vร  xรณa cรกc ฤ‘แป‘i tฦฐแปฃng.

Vรญ dแปฅ, giแบฃ sแปญ chรบng ta cรณ mแป™t แปฉng dแปฅng Express lฦฐu trแปฏ thรดng tin vแป sรกch trong cฦก sแปŸ dแปฏ liแป‡u. Chรบng ta cรณ thแปƒ tแบกo ra Book model, ฤ‘แป‹nh nghฤฉa cรกc field vร  behavior cแปงa mแป™t book object. Sau ฤ‘รณ, chรบng ta cรณ thแปƒ tแบกo ra mแป™t lแป›p BookRepository cung cแบฅp cรกc phฦฐฦกng thแปฉc ฤ‘แปƒ tแบกo, ฤ‘แปc, cแบญp nhแบญt vร  xรณa cรกc ฤ‘แป‘i tฦฐแปฃng sรกch trong cฦก sแปŸ dแปฏ liแป‡u.

Trong lแป›p BookRepository, chรบng ta cรณ thแปƒ ฤ‘แป‹nh nghฤฉa cรกc phฦฐฦกng thแปฉc nhฦฐ get_all_books vร  get_book_by_id ฤ‘แปƒ lแบฅy cรกc ฤ‘แป‘i tฦฐแปฃng sรกch tแปซ cฦก sแปŸ dแปฏ liแป‡u. Chรบng ta cลฉng cรณ thแปƒ ฤ‘แป‹nh nghฤฉa cรกc phฦฐฦกng thแปฉc nhฦฐ create_book vร  update_book ฤ‘แปƒ thรชm hoแบทc sแปญa ฤ‘แป•i cรกc book object trong cฦก sแปŸ dแปฏ liแป‡u.

Sแปญ dแปฅng mแบซu Repository vแป›i cฦก sแปŸ dแปฏ liแป‡u cรณ thแปƒ mang lแบกi nhiแปu lแปฃi รญch, bao gแป“m cแบฃi thiแป‡n khแบฃ nฤƒng kiแปƒm tra, bแบฃo trรฌ vร  linh hoแบกt.

Bแบฑng cรกch trแปซu tฦฐแปฃng hรณa lแป›p truy cแบญp cฦก sแปŸ dแปฏ liแป‡u khแปi phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng, cรกc nhร  phรกt triแปƒn cรณ thแปƒ dแป… dร ng chuyแปƒn ฤ‘แป•i giแปฏa cรกc cรดng nghแป‡ cฦก sแปŸ dแปฏ liแป‡u khรกc nhau hoแบทc thay ฤ‘แป•i lฦฐแปฃc ฤ‘แป“ cฦก sแปŸ dแปฏ liแป‡u mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng. Ngoร i ra, bแบฑng cรกch cung cแบฅp mแป™t tแบญp hแปฃp cรกc phฦฐฦกng thแปฉc ฤ‘แปƒ tฦฐฦกng tรกc vแป›i cฦก sแปŸ dแปฏ liแป‡u, mแบซu Repository cรณ thแปƒ giรบp viแป‡c viแบฟt cรกc bร i kiแปƒm tra cho แปฉng dแปฅng trแปŸ nรชn dแป… dร ng hฦกn.

// Define a Book interface that represents a book object
interface Book {
  id: number;
  title: string;
  author: string;
  publishedDate: Date;
}

// Define a BookRepository class that provides methods for interacting with a database of books
class BookRepository {
  private db: any; // Database connection object

  constructor(db: any) {
    this.db = db;
  }

  // Get all books from the database
  async getAllBooks(): Promise<Book[]> {
    const result = await this.db.query('SELECT * FROM books');
    return result.rows;
  }

  // Get a book by its ID
  async getBookById(id: number): Promise<Book> {
    const result = await this.db.query('SELECT * FROM books WHERE id = $1', [id]);
    return result.rows[0];
  }

  // Create a new book in the database
  async createBook(book: Book): Promise<void> {
    await this.db.query('INSERT INTO books (title, author, published_date) VALUES ($1, $2, $3)', [book.title, book.author, book.publishedDate]);
  }

  // Update an existing book in the database
  async updateBook(id: number, book: Book): Promise<void> {
    await this.db.query('UPDATE books SET title = $1, author = $2, published_date = $3 WHERE id = $4', [book.title, book.author, book.publishedDate, id]);
  }

  // Delete a book from the database
  async deleteBook(id: number): Promise<void> {
    await this.db.query('DELETE FROM books WHERE id = $1', [id]);
  }
}

// Example usage of the BookRepository class
const db = new Database(); // Instantiate a database connection object
const bookRepository = new BookRepository(db); // Instantiate a BookRepository object
const books = await bookRepository.getAllBooks(); // Get all books from the database
const book = await bookRepository.getBookById(1); // Get a book by its ID
const newBook = { title: 'New Book', author: 'Jane Doe', publishedDate: new Date() };
await bookRepository.createBook(newBook); // Create a new book in the database
await bookRepository.updateBook(1, { title: 'Updated Book', author: 'John Smith', publishedDate: new Date() }); // Update an existing book in the database
await bookRepository.deleteBook(1); // Delete a book from the database

Dependency Injection Pattern

Overview

Mแบซu Dependency Injection (DI) lร  mแป™t mแบซu thiแบฟt kแบฟ cho phรฉp tแบกo ra cรกc thร nh phแบงn phแบงn mแปm khรดng rร ng buแป™c chแบทt chแบฝ. Nรณ ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ giแบฃm bแป›t sแปฑ rร ng buแป™c giแปฏa cรกc thร nh phแบงn vร  cแบฃi thiแป‡n tรญnh linh hoแบกt, khแบฃ nฤƒng kiแปƒm thแปญ vร  khแบฃ nฤƒng bแบฃo trรฌ cแปงa mรฃ nguแป“n.

Trong mแบซu Dependency Injection, cรกc phแปฅ thuแป™c ฤ‘ฦฐแปฃc tiรชm vร o mแป™t thร nh phแบงn thay vรฌ ฤ‘ฦฐแปฃc tแบกo trong thร nh phแบงn ฤ‘รณ. ฤiแปu nร y cho phรฉp cรกc thร nh phแบงn ฤ‘ฦฐแปฃc tแบกo ra ฤ‘แป™c lแบญp vแป›i cรกc phแปฅ thuแป™c cแปงa chรบng, giรบp dแป… dร ng thay thแบฟ hoแบทc sแปญa ฤ‘แป•i cรกc phแปฅ thuแป™c mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn thร nh phแบงn chรญnh.

Cรณ ba loแบกi chรญnh cแปงa Dependency Injection: Constructor Injection (Tiรชm qua hร m tแบกo), Property Injection (Tiรชm qua thuแป™c tรญnh) vร  Method Injection (Tiรชm qua phฦฐฦกng thแปฉc).

Constructor Injection liรชn quan ฤ‘แบฟn viแป‡c truyแปn cรกc phแปฅ thuแป™c vร o mแป™t thร nh phแบงn thรดng qua hร m tแบกo cแปงa nรณ. Property Injection liรชn quan ฤ‘แบฟn viแป‡c ฤ‘แบทt cรกc phแปฅ thuแป™c thรดng qua cรกc thuแป™c tรญnh cรดng khai cแปงa thร nh phแบงn. Method Injection liรชn quan ฤ‘แบฟn viแป‡c truyแปn cรกc phแปฅ thuแป™c vร o cรกc phฦฐฦกng thแปฉc cแปงa thร nh phแบงn.

Mแป™t trong nhแปฏng lแปฃi รญch chรญnh cแปงa viแป‡c sแปญ dแปฅng mแบซu Dependency Injection lร  nรณ cแบฃi thiแป‡n khแบฃ nฤƒng kiแปƒm thแปญ cแปงa mรฃ nguแป“n. Bแบฑng cรกch tiรชm cรกc phแปฅ thuแป™c vร o mแป™t thร nh phแบงn, ta cรณ thแปƒ tแบกo cรกc bร i kiแปƒm tra ฤ‘ฦกn vแป‹ (unit tests) cรด lแบญp thร nh phแบงn khแปi cรกc phแปฅ thuแป™c cแปงa nรณ, giรบp dแป… dร ng kiแปƒm thแปญ thร nh phแบงn ฤ‘รณ mแป™t cรกch ฤ‘แป™c lแบญp.

Mแป™t lแปฃi รญch khรกc cแปงa viแป‡c sแปญ dแปฅng mแบซu Dependency Injection lร  nรณ lร m mรฃ nguแป“n linh hoแบกt vร  dแป… bแบฃo trรฌ hฦกn. Bแบฑng cรกch giแบฃm sแปฑ rร ng buแป™c giแปฏa cรกc thร nh phแบงn, ta dแป… dร ng sแปญa ฤ‘แป•i hoแบทc thay thแบฟ cรกc thร nh phแบงn mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn phแบงn cรฒn lแบกi cแปงa แปฉng dแปฅng.

Tแป•ng quรกt, mแบซu Dependency Injection lร  mแป™t cรดng cแปฅ hแปฏu รญch ฤ‘แปƒ tแบกo ra cรกc hแป‡ thแป‘ng backend cรณ khแบฃ nฤƒng mแปŸ rแป™ng, dแป… bแบฃo trรฌ vร  hiแป‡u quแบฃ. Nรณ giแบฃm sแปฑ rร ng buแป™c giแปฏa cรกc thร nh phแบงn vร  cแบฃi thiแป‡n tรญnh linh hoแบกt, khแบฃ nฤƒng kiแปƒm thแปญ vร  khแบฃ nฤƒng bแบฃo trรฌ cแปงa mรฃ nguแป“n.

Example of using the Dependency Injection pattern for decoupling dependencies

Trong ngแปฏ cแบฃnh phรกt triแปƒn backend, chรบng ta cรณ thแปƒ sแปญ dแปฅng Dependency Injection ฤ‘แปƒ tรกch rแปi cรกc thร nh phแบงn cแปงa แปฉng dแปฅng khแปi viแป‡c triแปƒn khai cแปฅ thแปƒ cแปงa cรกc dแป‹ch vแปฅ hoแบทc thฦฐ viแป‡n bรชn ngoร i, chแบณng hแบกn nhฦฐ cฦก sแปŸ dแปฏ liแป‡u, bแป™ nhแป› cache hoแบทc nhร  cung cแบฅp email. ฤiแปu nร y cho phรฉp chรบng ta dแป… dร ng chuyแปƒn ฤ‘แป•i giแปฏa cรกc triแปƒn khai khรกc nhau cแปงa cรกc dแป‹ch vแปฅ nร y hoแบทc tแบกo giแบฃ ฤ‘แป‘i tฦฐแปฃng (mock) chรบng trong quรก trรฌnh kiแปƒm thแปญ.

Dฦฐแป›i ฤ‘รขy lร  mแป™t vรญ dแปฅ vแป viแป‡c sแปญ dแปฅng Dependency Injection trong mแป™t แปฉng dแปฅng TypeScript tฦฐฦกng tรกc vแป›i cฦก sแปŸ dแปฏ liแป‡u:

// Define an interface for a database connection object
interface DatabaseConnection {
  query(sql: string, params?: any[]): Promise<any>;
}

// Define a class for a PostgreSQL database connection
class PostgresConnection implements DatabaseConnection {
  private client: any; // PostgreSQL client object

  constructor() {
    this.client = new PostgreSQLClient(); // Instantiate a PostgreSQL client object
    this.client.connect(); // Connect to the database
  }

  async query(sql: string, params?: any[]): Promise<any> {
    const result = await this.client.query(sql, params);
    return result.rows;
  }
}

// Define a class for a BookService that depends on a database connection
class BookService {
  private db: DatabaseConnection; // Database connection object

  constructor(db: DatabaseConnection) {
    this.db = db;
  }

  async getAllBooks(): Promise<Book[]> {
    const result = await this.db.query('SELECT * FROM books');
    return result.map((row: any) => ({ id: row.id, title: row.title, author: row.author, publishedDate: row.published_date }));
  }

  async getBookById(id: number): Promise<Book> {
    const result = await this.db.query('SELECT * FROM books WHERE id = $1', [id]);
    return { id: result.id, title: result.title, author: result.author, publishedDate: result.published_date };
  }

  async createBook(book: Book): Promise<void> {
    await this.db.query('INSERT INTO books (title, author, published_date) VALUES ($1, $2, $3)', [book.title, book.author, book.publishedDate]);
  }

  async updateBook(id: number, book: Book): Promise<void> {
    await this.db.query('UPDATE books SET title = $1, author = $2, published_date = $3 WHERE id = $4', [book.title, book.author, book.publishedDate, id]);
  }

  async deleteBook(id: number): Promise<void> {
    await this.db.query('DELETE FROM books WHERE id = $1', [id]);
  }
}

// Example usage of the BookService class with a PostgresConnection object
const db = new PostgresConnection(); // Instantiate a PostgresConnection object
const bookService = new BookService(db); // Instantiate a BookService object with the PostgresConnection object as its dependency
const books = await bookService.getAllBooks(); // Get all books from the database
const book = await bookService.getBookById(1); // Get a book by its ID
const newBook = { title: 'New Book', author: 'Jane Doe', publishedDate: new Date() };
await bookService.createBook(newBook); // Create a new book in the database
await bookService.updateBook(1, { title: 'Updated Book', author: 'John Smith', publishedDate: new Date() }); //

Trong Spring Boot, DI lร  viแป‡c cรกc Object nรชn phแปฅ thuแป™c vร o cรกc abstract class vร  instance chi tiแบฟt cแปงa nรณ sแบฝ ฤ‘ฦฐแปฃc Inject vร o ฤ‘แป‘i tฦฐแปฃng lรบc runtime.

Observer Pattern

Overview

Mแบซu Observer lร  mแป™t mแบซu thiแบฟt kแบฟ cho phรฉp mแป™t object (gแปi lร  subject) thรดng bรกo cho cรกc object khรกc (gแปi lร  observers) khi trแบกng thรกi cแปงa nรณ thay ฤ‘แป•i. Nรณ cung cแบฅp mแป™t cรกch cho cรกc object giao tiแบฟp vแป›i nhau mร  khรดng cแบงn biแบฟt trแปฑc tiแบฟp sแปฑ tแป“n tแบกi cแปงa nhau.

Trong mแบซu Observer, subject duy trรฌ mแป™t danh sรกch cรกc observers vร  thรดng bรกo cho chรบng khi trแบกng thรกi cแปงa nรณ thay ฤ‘แป•i. Cรกc observers sau ฤ‘รณ cรณ thแปƒ thแปฑc hiแป‡n hร nh ฤ‘แป™ng dแปฑa trรชn sแปฑ thay ฤ‘แป•i trong trแบกng thรกi cแปงa subject. ฤiแปu nร y cho phรฉp mแป‘i quan hแป‡ giแปฏa subject vร  observers lร  lแปng lแบปo, lร m cho viแป‡c sแปญa ฤ‘แป•i hoแบทc mแปŸ rแป™ng hแป‡ thแป‘ng dแป… dร ng hฦกn.

Mแป™t trong nhแปฏng lแปฃi รญch chรญnh cแปงa viแป‡c sแปญ dแปฅng mแบซu Observer lร  nรณ cแบฃi thiแป‡n tรญnh mรด-ฤ‘un vร  tรญnh linh hoแบกt cแปงa mรฃ nguแป“n. Bแบฑng cรกch tรกch biแป‡t subject vร  observers, ta cรณ thแปƒ thรชm hoแบทc xรณa observers mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn subject, hoแบทc thรชm cรกc subject mแป›i mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn observers hiแป‡n cรณ.

Mแป™t lแปฃi รญch khรกc cแปงa viแป‡c sแปญ dแปฅng mแบซu Observer lร  nรณ cรณ thแปƒ cแบฃi thiแป‡n hiแป‡u suแบฅt cแปงa hแป‡ thแป‘ng. Bแบฑng cรกch thรดng bรกo chแป‰ cho cรกc observers quan tรขm ฤ‘แบฟn sแปฑ thay ฤ‘แป•i, ta cรณ thแปƒ giแบฃm sแป‘ lฦฐแปฃng thรดng bรกo vร  cแบฃi thiแป‡n hiแป‡u suแบฅt tแป•ng thแปƒ cแปงa hแป‡ thแป‘ng.

Example of using the Observer pattern for event-driven programming

Giแบฃ sแปญ chรบng ta cรณ mแป™t แปฉng dแปฅng web cho phรฉp ngฦฐแปi dรนng ฤ‘ฤƒng kรฝ cรกc chแปง ฤ‘แป quan tรขm khรกc nhau. Khi cรณ nแป™i dung mแป›i ฤ‘ฦฐแปฃc thรชm vร o chแปง ฤ‘แป ฤ‘รฃ ฤ‘ฤƒng kรฝ, ngฦฐแปi dรนng sแบฝ nhแบญn ฤ‘ฦฐแปฃc thรดng bรกo. Chรบng ta cรณ thแปƒ triแปƒn khai tรญnh nฤƒng nร y bแบฑng cรกch sแปญ dแปฅng mแบซu Observer.

ฤแบงu tiรชn, chรบng ta ฤ‘แป‹nh nghฤฉa giao diแป‡n subject Topic, sแบฝ thรดng bรกo cho cรกc observers (subscribers) vแป bแบฅt kแปณ cแบญp nhแบญt nร o:

interface Topic {
  subscribe(observer: Observer): void;
  unsubscribe(observer: Observer): void;
  notify(): void;
}

Sau ฤ‘รณ, chรบng ta triแปƒn khai giao diแป‡n Topic trong mแป™t lแป›p chแปง ฤ‘แป cแปฅ thแปƒ lร  TopicManager, quแบฃn lรฝ mแป™t danh sรกch cรกc ngฦฐแปi ฤ‘ฤƒng kรฝ vร  thรดng bรกo cho hแป mแป—i khi cรณ nแป™i dung mแป›i ฤ‘ฦฐแปฃc thรชm vร o:

class TopicManager implements Topic {
  private subscribers: Observer[] = [];

  public subscribe(observer: Observer): void {
    this.subscribers.push(observer);
  }

  public unsubscribe(observer: Observer): void {
    const index = this.subscribers.indexOf(observer);
    if (index !== -1) {
      this.subscribers.splice(index, 1);
    }
  }

  public notify(): void {
    for (const subscriber of this.subscribers) {
      subscriber.update();
    }
  }

  public addContent(topic: string, content: string): void {
    // Add new content to the topic
    // ...

    // Notify all subscribers of the new content
    this.notify();
  }
}

Tiแบฟp theo, chรบng ta ฤ‘แป‹nh nghฤฉa observer interface, cรณ 1 update method sแบฝ ฤ‘ฦฐแปฃc gแปi bแปŸi subject:

interface Observer {
  update(): void;
}

Chรบng ta triแปƒn khai Observer interface trong concrete observer class, User, lแป›p nร y sแบฝ nhแบญn ฤ‘ฦฐแปฃc thรดng bรกo khi nแป™i dung mแป›i ฤ‘ฦฐแปฃc thรชm vร o chแปง ฤ‘แป ฤ‘รฃ ฤ‘ฤƒng kรญ:

class User implements Observer {
  private readonly username: string;

  constructor(username: string) {
    this.username = username;
  }

  public update(): void {
    console.log(`[${this.username}] New content has been added to a subscribed topic`);
  }
}

Cuแป‘i cรนng, chรบng ta cรณ thแปƒ sแปญ dแปฅng TopicManager and User classes ฤ‘แปƒ triแปƒn khai features ฤ‘ฤƒng kรฝ:

// Create a new topic manager
const topicManager = new TopicManager();

// Create two users
const user1 = new User("Alice");
const user2 = new User("Bob");

// Subscribe the users to a topic
topicManager.subscribe(user1);
topicManager.subscribe(user2);

// Add new content to the topic
topicManager.addContent("science", "New scientific discovery!");

// Output:
// [Alice] New content has been added to a subscribed topic
// [Bob] New content has been added to a subscribed topic

Trong vรญ dแปฅ nร y, TopicManager ฤ‘รณng vai trรฒ lร  chแปง ฤ‘แป (subject) vร  lแป›p User ฤ‘รณng vai trรฒ lร  ngฦฐแปi quan sรกt (observer).

TopicManager duy trรฌ mแป™t danh sรกch cรกc ngฦฐแปi ฤ‘ฤƒng kรฝ (subscribers) vร  thรดng bรกo cho hแป mแป—i khi cรณ nแป™i dung mแป›i ฤ‘ฦฐแปฃc thรชm vร o chแปง ฤ‘แป mร  hแป ฤ‘รฃ ฤ‘ฤƒng kรฝ. Lแป›p User nhแบญn thรดng bรกo vร  thแปฑc hiแป‡n mแป™t sแป‘ hร nh ฤ‘แป™ng, chแบณng hแบกn nhฦฐ hiแปƒn thแป‹ thรดng bรกo cho ngฦฐแปi dรนng.

Mรด hรฌnh Observer cho phรฉp chรบng ta tรกch rแปi chแปง ฤ‘แป vร  ngฦฐแปi quan sรกt, giรบp dแป… dร ng thรชm hoแบทc xรณa cรกc ngฦฐแปi ฤ‘ฤƒng kรฝ mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn phแบงn cรฒn lแบกi cแปงa hแป‡ thแป‘ng.

Decorator Pattern

Mรด hรฌnh Decorator lร  mแป™t mรด hรฌnh thiแบฟt kแบฟ cho phรฉp thรชm hร nh vi vร o mแป™t ฤ‘แป‘i tฦฐแปฃng cรก nhรขn, cแบฃ tฤฉnh vร  ฤ‘แป™ng, mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn hร nh vi cแปงa cรกc ฤ‘แป‘i tฦฐแปฃng khรกc cรนng lแป›p. Nรณ ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ thรชm chแปฉc nฤƒng vร o cรกc ฤ‘แป‘i tฦฐแปฃng trong thแปi gian chแบกy, thay vรฌ thแปi gian biรชn dแป‹ch.

Trong mรด hรฌnh Decorator, mแป™t lแป›p decorator ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ bao bแปc ฤ‘แป‘i tฦฐแปฃng gแป‘c. Lแป›p decorator cรณ cรนng giao diแป‡n vแป›i ฤ‘แป‘i tฦฐแปฃng gแป‘c, cho phรฉp sแปญ dแปฅng nรณ theo cรนng cรกch. Lแป›p decorator sau ฤ‘รณ thรชm hร nh vi vร o ฤ‘แป‘i tฦฐแปฃng gแป‘c bแบฑng cรกch chuyแปƒn giao mแป™t phแบงn cรดng viแป‡c cho ฤ‘แป‘i tฦฐแปฃng ฤ‘ฦฐแปฃc bao bแปc vร  thรชm hร nh vi riรชng cแปงa mรฌnh.

Mแป™t trong nhแปฏng lแปฃi รญch chรญnh cแปงa viแป‡c sแปญ dแปฅng mรด hรฌnh Decorator lร  cho phรฉp thรชm chแปฉc nฤƒng vร o cรกc ฤ‘แป‘i tฦฐแปฃng mแป™t cรกch ฤ‘แป™ng. ฤiแปu nร y cรณ thแปƒ hแปฏu รญch trong nhแปฏng tรฌnh huแป‘ng mร  hร nh vi cแปงa mแป™t ฤ‘แป‘i tฦฐแปฃng cแบงn ฤ‘ฦฐแปฃc thay ฤ‘แป•i trong thแปi gian chแบกy, hoแบทc khi hร nh vi cแปงa mแป™t ฤ‘แป‘i tฦฐแปฃng cแบงn ฤ‘ฦฐแปฃc mแปŸ rแป™ng mร  khรดng thay ฤ‘แป•i giao diแป‡n cแปงa nรณ.

Lแปฃi รญch khรกc cแปงa viแป‡c sแปญ dแปฅng mรด hรฌnh Decorator lร  nรณ cรณ thแปƒ cแบฃi thiแป‡n khแบฃ nฤƒng bแบฃo trรฌ cแปงa mรฃ nguแป“n. Vรฌ hร nh vi cแปงa ฤ‘แป‘i tฦฐแปฃng ฤ‘ฦฐแปฃc phรขn tรกch thร nh cรกc decorator riรชng lแบป, nรชn dแป… dร ng chแป‰nh sแปญa hoแบทc mแปŸ rแป™ng hร nh vi cแปงa ฤ‘แป‘i tฦฐแปฃng mร  khรดng แบฃnh hฦฐแปŸng ฤ‘แบฟn cรกc phแบงn khรกc cแปงa hแป‡ thแป‘ng.

Tแป•ng thแปƒ, mรด hรฌnh Decorator lร  mแป™t cรดng cแปฅ hแปฏu รญch ฤ‘แปƒ tแบกo ra cรกc hแป‡ thแป‘ng backend cรณ khแบฃ nฤƒng mแปŸ rแป™ng, dแป… bแบฃo trรฌ vร  hiแป‡u quแบฃ. Nรณ cho phรฉp thรชm chแปฉc nฤƒng vร o cรกc ฤ‘แป‘i tฦฐแปฃng mแป™t cรกch ฤ‘แป™ng, cแบฃi thiแป‡n tรญnh linh hoแบกt vร  khแบฃ nฤƒng bแบฃo trรฌ cแปงa mรฃ nguแป“n.

Example of using the Decorator pattern for adding functionality to a class dynamically

Giแบฃ sแปญ chรบng ta cรณ 1 class Car ฤ‘แบกi diแป‡n cho 1 basic car vแป›i cรกc properties and methods:

class Car {
  private make: string;
  private model: string;
  private year: number;
  private price: number;

  constructor(make: string, model: string, year: number, price: number) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.price = price;
  }

  public getMake(): string {
    return this.make;
  }

  public getModel(): string {
    return this.model;
  }

  public getYear(): number {
    return this.year;
  }

  public getPrice(): number {
    return this.price;
  }
}

Chรบng ta sแปญ dแปฅng mรด hรฌnh Decorator ฤ‘แปƒ thรชm cรกc chแปฉc nฤƒng bแป• sung vร o lแป›p Car, chแบณng hแบกn nhฦฐ tรญnh toรกn thuแบฟ bรกn hร ng trรชn giรก xe vร  thรชm mแป™t sแป‘ tรญnh nฤƒng tรนy chแปn cho xe, nhฦฐ hแป‡ thแป‘ng ฤ‘แป‹nh vแป‹ vร  cแปญa sแป• trแปi. Chรบng ta cรณ thแปƒ thรชm cรกc tรญnh nฤƒng nร y vร o lแป›p Car mแป™t cรกch ฤ‘แป™ng bแบฑng cรกch sแปญ dแปฅng mรด hรฌnh Decorator.

ฤแบงu tiรชn, chรบng ta ฤ‘แป‹nh nghฤฉa mแป™t lแป›p cฦก sแปŸ trแปซu tฦฐแปฃng CarFeature mร  tแบฅt cแบฃ cรกc decorator sแบฝ kแบฟ thแปซa tแปซ ฤ‘รณ:

abstract class CarFeature extends Car {
  protected car: Car;

  constructor(car: Car) {
    super(car.getMake(), car.getModel(), car.getYear(), car.getPrice());
    this.car = car;
  }

  public abstract getPrice(): number;
}

Tiแบฟp theo, chรบng ta triแปƒn khai cรกc concrete decorator class ฤ‘แปƒ thรชm cรกc freatures mong muแป‘n cho lแป›p car:

class SalesTaxDecorator extends CarFeature {
  public getPrice(): number {
    return this.car.getPrice() * 1.10; // 10% sales tax
  }
}

class NavigationDecorator extends CarFeature {
  public getPrice(): number {
    return this.car.getPrice() + 1500; // add $1500 for navigation system
  }
}

class SunroofDecorator extends CarFeature {
  public getPrice(): number {
    return this.car.getPrice() + 1000; // add $1000 for sunroof
  }
}

Sau ฤ‘รณ, chรบng ta dรนng decorators nร y ฤ‘แปƒ thรชm functionally vร o lแป›p car 1 cรกch dynamically:

// Create a basic car
const car = new Car("Honda", "Accord", 2022, 25000);

// Add sales tax to the car
const carWithSalesTax = new SalesTaxDecorator(car);

// Add a navigation system to the car
const carWithNavigation = new NavigationDecorator(carWithSalesTax);

// Add a sunroof to the car
const carWithSunroof = new SunroofDecorator(carWithNavigation);

console.log(`Make: ${carWithSunroof.getMake()}`);
console.log(`Model: ${carWithSunroof.getModel()}`);
console.log(`Year: ${carWithSunroof.getYear()}`);
console.log(`Price: ${carWithSunroof.getPrice()}`);

// Output:
// Make: Honda
// Model: Accord
// Year: 2022
// Price: 28750

Trong vรญ dแปฅ nร y, chรบng ta sแปญ dแปฅng mรด hรฌnh Decorator ฤ‘แปƒ thรชm chแปฉc nฤƒng vร o mแป™t ฤ‘แป‘i tฦฐแปฃng Car mแป™t cรกch ฤ‘แป™ng. Mแป—i decorator kแบฟ thแปซa tแปซ lแป›p trแปซu tฦฐแปฃng CarFeature vร  thรชm mแป™t sแป‘ chแปฉc nฤƒng bแป• sung vร o ฤ‘แป‘i tฦฐแปฃng Car.

Chรบng ta cรณ thแปƒ thรชm nhiแปu decorator vร o mแป™t ฤ‘แป‘i tฦฐแปฃng Car theo bแบฅt kแปณ thแปฉ tแปฑ nร o vร  mแป—i decorator ฤ‘แปu thรชm chแปฉc nฤƒng riรชng cแปงa nรณ vร o ฤ‘แป‘i tฦฐแปฃng. ฤiแปu nร y cho phรฉp chรบng ta tแบกo ra cรกc ฤ‘แป‘i tฦฐแปฃng Car ฤ‘ฦฐแปฃc tรนy chแป‰nh cao vแป›i chแป‰ cรกc tรญnh nฤƒng chรบng ta cแบงn, trong khi vแบซn giแปฏ cho lแป›p Car cแป‘t lรตi ฤ‘ฦกn giแบฃn vร  dแป… bแบฃo trรฌ.

Last updated