TYPESCRIPT 2.X CĂN BẢN
Hàm trong TypeScript Sử dụng hàm generics Sử dụng hàm generics trong TypeScript Sử dụng Array trong TypeScript Sử dụng Tuple trong TypeScript Sử dụng kiểu Array, Tuple, Enum trong TypeScript Interface trong Typescript Hybrid Types với Interface trong TypeScript Khác biệt khi sử dụng 'type' và 'interface' trong TypeScript Cách dùng Enum trong TypeScript Types và interface trong TypeScript Class trong TypeScript Sử dụng Abstract Classes trong TypeScript Sử dụng Interface trong Typescript (phần 2) Sử dụng Casting trong TypeScript Tìm hiểu về Generics trong TypeScript Tìm hiểu về utility types trong Typescript Utility types phổ biến trong Typescript Sử dụng default parameters trong TypeScript Modules trong TypeScript Rest Parameters trong TypeScript Sử dụng Function Overloadings trong TypeScript Sử dụng Type Assertions trong TypeScript Sử dụng Static Methods và Properties trong TypeScript. Sử dụng Access Modifiers trong TypeScript 10 mẹo và thủ thuật hay nhất trong TypeScript 5 Cách giúp bạn loại bỏ "any" trong TypeScript Mapped Types trong TypeScript Dependency Injection trong Typescript 5 ký hiệu khó hiểu cần biết trong TypeScript Cách sử dụng @ts-expect-error trong Typescript Declaration Merging trong TypeScript Tìm hiểu Branded Type trong TypeScript Namespaces trong Typescript Phân biệt Modules và Namespaces trong TypeScript Triple-Slash Directives trong TypeScript là gì? Phần 1: Biến trong TypeScript Phần 2: Biến trong TypeScript Property trong TypeScript Phân tích JSON trong TypeScript Bài tập TypeScript: Các dạng bài tập cơ bản Bài tập TypeScript: Lập trình Hướng đối tượng trong TypeScript Bài tập TypeScript: Kiểu Generic Types trong Typescript Bài tập TypeScript: Các kiểu dữ liệu mảng và tuple. Bài tập TypeScript: Classes và Inheritance trong Typescript Bài 01: TypeScript là gì? TypeScript và Javascript Bài 02: Cài đặt TypeScript Bài 03: TypeScript Basic Types Bài 04: Khai báo biến trong TypeScript Bài 05: Lệnh If Else và Switch Case trong TypeScript Bài 06: Vòng lặp trong TypeScript
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Dependency Injection trong Typescript

Dependency Injection (DI) là một cách để cung cấp các phụ thuộc cho một thành phần (component) thay vì để thành phần đó tự tạo ra hoặc quản lý các phụ thuộc của nó. Điều này giúp giảm sự ràng buộc giữa các thành phần, làm cho ứng dụng dễ bảo trì, mở rộng, và kiểm thử hơn.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Trong bài viết này, mình sẽ tìm hiểu các khía cạnh quan trọng của Dependency Injection trong TypeScript, từ cách sử dụng, lợi ích, đến việc thực hành trong các ví dụ cụ thể và ứng dụng thực tế. Hãy cùng bắt đầu với việc giới thiệu về Dependency Injection và tại sao nó quan trọng trong phát triển phần mềm hiện đại.

Dependency Injection là gì?

t E1 BA A3i 20xu E1 BB 91ng 20 3  jpg

Dependency Injection (DI) là một nguyên tắc trong phát triển phần mềm, nơi mà các phụ thuộc (dependencies) của một thành phần (component) không được tạo ra hoặc quản lý bởi thành phần đó mà được cung cấp từ bên ngoài. Điều này giúp giảm sự ràng buộc giữa các thành phần và làm cho ứng dụng trở nên linh hoạt, dễ bảo trì, và dễ mở rộng.

Trong Dependency Injection:

Bài viết này được đăng tại [free tuts .net]

  • Dependencies được cung cấp từ bên ngoài: Thay vì để một thành phần tự tạo ra hoặc quản lý các dependencies của nó, dependencies được cung cấp từ bên ngoài. Điều này thường được thực hiện thông qua việc tiêm dependencies vào thành phần (injecting dependencies), thay vì thành phần tự tạo ra chúng.

  • Loại bỏ ràng buộc cứng: Dependency Injection giúp loại bỏ sự ràng buộc cứng (hard-coding) giữa các thành phần. Thay vì phụ thuộc trực tiếp vào cụ thể của các dependencies, các dependencies có thể thay đổi hoặc được thay thế bởi các phiên bản khác mà không làm ảnh hưởng đến thành phần sử dụng chúng.

  • Dễ kiểm thử: Dependency Injection làm cho việc kiểm thử (unit testing) trở nên dễ dàng hơn. Bạn có thể dễ dàng cung cấp các dependencies giả (mock dependencies) trong quá trình kiểm thử mà không cần thay đổi mã nguồn của thành phần gốc.

Dependency Injection thường được áp dụng trong các ứng dụng lớn, phức tạp và trong việc phát triển các frameworks và thư viện. Nó giúp tạo ra các ứng dụng có khả năng mở rộng và dễ bảo trì hơn và giảm rủi ro khi phát triển ứng dụng.

Cách sử dụng Dependency Injection

1 0P 1JhnUaZeobDUAajIbhA e1627957432652 jpeg

Tiêm phụ thuộc (Inject Dependencies)

Việc tiêm (inject) các phụ thuộc vào các thành phần của ứng dụng là một phần quan trọng của Dependency Injection. Điều này đảm bảo rằng các thành phần có thể sử dụng các dependencies mà chúng cần mà không cần biết chi tiết cụ thể về cách dependencies được tạo ra hoặc quản lý.

Ví dụ:

class Database {
    // Đây có thể là một lớp quản lý kết nối đến cơ sở dữ liệu
    constructor() {
        // Khởi tạo kết nối đến cơ sở dữ liệu
    }

    query(sql: string) {
        // Thực hiện truy vấn SQL
    }
}

class ProductService {
    private db: Database;

    constructor(database: Database) {
        this.db = database;
    }

    getProduct(productId: number) {
        const productData = this.db.query(`SELECT * FROM products WHERE id = ${productId}`);
        // Xử lý dữ liệu và trả về sản phẩm
    }
}

Trong ví dụ trên, ProductService cần sử dụng một thể hiện của lớp Database để thực hiện truy vấn cơ sở dữ liệu. Thay vì tạo ra thể hiện của Database bên trong ProductService, mình tiêm Database vào ProductService thông qua constructor, cho phép sử dụng một thể hiện của Database được cung cấp từ bên ngoài.

Containers (Containers of Dependencies)

Containers (hoặc còn gọi là IoC containers) là các đối tượng quản lý và cung cấp các phụ thuộc cho các thành phần của ứng dụng. Containers giúp quản lý việc tạo ra và tiêm các phụ thuộc, giảm sự phức tạp của việc quản lý phụ thuộc thủ công.

Ví dụ:

class Database {
    // Đây có thể là một lớp quản lý kết nối đến cơ sở dữ liệu
    constructor() {
        // Khởi tạo kết nối đến cơ sở dữ liệu
    }

    query(sql: string) {
        // Thực hiện truy vấn SQL
    }
}

class ProductService {
    private db: Database;

    constructor(database: Database) {
        this.db = database;
    }

    getProduct(productId: number) {
        const productData = this.db.query(`SELECT * FROM products WHERE id = ${productId}`);
        // Xử lý dữ liệu và trả về sản phẩm
    }
}

class IoCContainer {
    private static instances = new Map<any, any>();

    static resolve<T>(dependency: { new(): T }) {
        if (!this.instances.has(dependency)) {
            this.instances.set(dependency, new dependency());
        }
        return this.instances.get(dependency);
    }
}

const database = IoCContainer.resolve(Database);
const productService = IoCContainer.resolve(ProductService);

Trong ví dụ này, IoCContainer là một container đơn giản. Nó quản lý các thể hiện của các phụ thuộc và cung cấp chúng cho các thành phần khi cần. ProductService và Database không cần biết chi tiết cụ thể về cách dependencies được tạo ra và quản lý, mà chỉ cần yêu cầu chúng từ container.

TypeScript và Dependency Injection

Typed Dependencies

Một trong những lợi ích quan trọng của việc sử dụng TypeScript trong Dependency Injection là khả năng kiểm tra kiểu dữ liệu của các phụ thuộc trong quá trình phát triển ứng dụng. TypeScript giúp đảm bảo rằng bạn sử dụng các phụ thuộc với kiểu dữ liệu chính xác, giúp tránh các lỗi kiểu dữ liệu trong quá trình chạy ứng dụng.

Ví dụ:

class Logger {
    log(message: string) {
        console.log(message);
    }
}

class ProductService {
    private logger: Logger;

    constructor(logger: Logger) {
        this.logger = logger;
    }

    getProduct(productId: number) {
        this.logger.log(`Getting product with ID ${productId}`);
        // Xử lý dữ liệu và trả về sản phẩm
    }
}

Trong ví dụ này, Logger là một phụ thuộc của ProductService. TypeScript sẽ đảm bảo rằng bạn sử dụng Logger với kiểu dữ liệu chính xác trong constructor của `ProductService. Điều này giúp tránh lỗi kiểu dữ liệu và tăng tính kiểm tra trong quá trình phát triển.

Nếu bạn cố gắng sử dụng một phụ thuộc với kiểu dữ liệu không phù hợp, TypeScript sẽ cảnh báo bạn về lỗi và giúp bạn sửa chúng trước khi chạy ứng dụng.

Typed Dependencies là một trong những lợi ích quan trọng của việc sử dụng TypeScript trong Dependency Injection, giúp đảm bảo tính toàn vẹn và độ tin cậy của mã nguồn.

Ví dụ cụ thể

Để minh họa việc sử dụng Dependency Injection trong TypeScript, sẽ xem xét một ví dụ đơn giản về việc quản lý phụ thuộc của một ứng dụng.

Ví dụ: Dependency Injection trong Một Ứng Dụng ToDo List

Giả sử mình đang xây dựng một ứng dụng ToDo List đơn giản trong TypeScript. Trong ứng dụng này, mình cần quản lý danh sách công việc (tasks) và lưu trữ chúng trong một cơ sở dữ liệu. Ta cũng muốn có khả năng ghi log các hoạt động và hiển thị thông báo.

class Task {
    constructor(public id: number, public description: string, public completed: boolean) {}
}

interface Logger {
    log(message: string): void;
}

class ConsoleLogger implements Logger {
    log(message: string) {
        console.log(message);
    }
}

interface Database {
    saveTask(task: Task): void;
    getTasks(): Task[];
}

class InMemoryDatabase implements Database {
    private tasks: Task[] = [];

    saveTask(task: Task) {
        this.tasks.push(task);
    }

    getTasks() {
        return this.tasks;
    }
}

class TaskManager {
    constructor(private logger: Logger, private database: Database) {}

    createTask(description: string) {
        const id = this.database.getTasks().length + 1;
        const task = new Task(id, description, false);
        this.database.saveTask(task);
        this.logger.log(`Created new task with ID ${id}`);
    }
}

const logger = new ConsoleLogger();
const database = new InMemoryDatabase();
const taskManager = new TaskManager(logger, database);

taskManager.createTask("Finish the TypeScript article");

Trong ví dụ này, mình có ba phụ thuộc: Logger, Database, và TaskManager. Dependency Injection cho phép mình cung cấp các phụ thuộc này vào TaskManager mà không cần biết chi tiết cụ thể về cách chúng được tạo ra hoặc quản lý.

Kết bài

Dependency Injection (DI) là một nguyên tắc mạnh mẽ và quan trọng trong phát triển phần mềm, và việc áp dụng nó trong TypeScript mang lại nhiều lợi ích cho việc quản lý phụ thuộc và tích hợp các thành phần trong ứng dụng. Trong bài viết này, mình đã tìm hiểu về cách sử dụng DI để tiêm phụ thuộc và quản lý chúng thông qua containers. Mình cũng đã thấy cách TypeScript giúp kiểm tra kiểu dữ liệu của các phụ thuộc và đảm bảo tính toàn vẹn của mã nguồn.

Việc sử dụng Dependency Injection không chỉ giúp tạo ra mã nguồn dễ bảo trì, mở rộng, và kiểm thử, mà còn là một phần quan trọng trong việc phát triển các ứng dụng lớn và phức tạp. Nó giúp giảm ràng buộc giữa các thành phần và làm cho mã nguồn dễ đọc và hiểu hơn.

Hãy tận dụng kiến thức về Dependency Injection và TypeScript để xây dựng các ứng dụng chất lượng cao và dễ quản lý.

Cùng chuyên mục:

Bài tập TypeScript: Classes và Inheritance trong Typescript

Bài tập TypeScript: Classes và Inheritance trong Typescript

Bài tập TypeScript: Các kiểu dữ liệu mảng và tuple.

Bài tập TypeScript: Các kiểu dữ liệu mảng và tuple.

Bài tập TypeScript: Kiểu Generic Types trong Typescript

Bài tập TypeScript: Kiểu Generic Types trong Typescript

Bài tập TypeScript: Lập trình Hướng đối tượng trong TypeScript

Bài tập TypeScript: Lập trình Hướng đối tượng trong TypeScript

Bài tập TypeScript: Các dạng bài tập cơ bản

Bài tập TypeScript: Các dạng bài tập cơ bản

Phân tích JSON trong TypeScript

Phân tích JSON trong TypeScript

Property trong TypeScript

Property trong TypeScript

Phần 2: Biến trong TypeScript

Phần 2: Biến trong TypeScript

Phần 1: Biến trong TypeScript

Phần 1: Biến trong TypeScript

Triple-Slash Directives trong TypeScript là gì?

Triple-Slash Directives trong TypeScript là gì?

Phân biệt Modules và Namespaces trong TypeScript

Phân biệt Modules và Namespaces trong TypeScript

Tìm hiểu Branded Type trong TypeScript

Tìm hiểu Branded Type trong TypeScript

Namespaces trong Typescript

Namespaces trong Typescript

Declaration Merging trong TypeScript

Declaration Merging trong TypeScript

Cách sử dụng @ts-expect-error trong typescript

Cách sử dụng @ts-expect-error trong typescript

5 ký hiệu khó hiểu cần biết trong TypeScript

5 ký hiệu khó hiểu cần biết trong TypeScript

Mapped Types trong TypeScript

Mapped Types trong TypeScript

5 Cách giúp bạn loại bỏ

5 Cách giúp bạn loại bỏ "any" trong TypeScript

10 mẹo và thủ thuật hay nhất trong TypeScript

10 mẹo và thủ thuật hay nhất trong TypeScript

Sử dụng Access Modifiers trong TypeScript

Sử dụng Access Modifiers trong TypeScript

Top