1. Dart OOP là gì?

Dart OOP là lập trình hướng đối tượng (Object-Oriented Programming) trong ngôn ngữ Dart. Đây là phương pháp lập trình tổ chức chương trình xoay quanh đối tượng (Object) thay vì chỉ sử dụng các biến và hàm riêng lẻ.

Trong OOP, một đối tượng thường có dữ liệu và hành vi. Dữ liệu mô tả đặc điểm của đối tượng, còn hành vi mô tả những việc đối tượng có thể thực hiện.

Ví dụ, trong một ứng dụng bán hàng, một sản phẩm có thể có tên, giá, số lượng và các hành động như tính giá hoặc hiển thị thông tin. Những dữ liệu và hành động này có thể được gom lại thành một đối tượng Product.

Để tạo ra các đối tượng, Dart sử dụng Class. Class có thể hiểu là một khuôn mẫu mô tả đối tượng sẽ có những dữ liệu và hành vi gì.

Có thể hiểu mối quan hệ cơ bản như sau:

Class → Object → Dữ liệu + Hành vi

Dart OOP giúp chương trình có cấu trúc rõ ràng hơn, dễ quản lý, dễ tái sử dụng và dễ mở rộng. Đây là kiến thức nền tảng rất quan trọng đối với Flutter vì Flutter được xây dựng bằng Dart và sử dụng Class, Object cùng các đặc điểm của OOP ở hầu hết các thành phần.

  1. Class là gì?

Class là khuôn mẫu dùng để mô tả cấu trúc và hành vi của một nhóm đối tượng.

Class không phải là một đối tượng cụ thể mà chỉ là bản thiết kế cho đối tượng. Trong Class thường có:

  • Property/Field: dùng để lưu trữ dữ liệu.
  • Method: dùng để mô tả hành vi hoặc chức năng.
  • Constructor: dùng để khởi tạo Object.

Ví dụ đơn giản:

class Student {
  String name;
  int age;
  Student(this.name, this.age);
}

Trong ví dụ trên, Student là Class, còn name và age là dữ liệu mà mỗi Object Student có thể sở hữu.

Class giúp lập trình viên mô tả một đối tượng một cách có tổ chức thay vì phải quản lý từng biến riêng lẻ.

  1. Object là gì?

Object là một đối tượng cụ thể được tạo ra từ Class.

Nếu Class là khuôn mẫu thì Object là sản phẩm được tạo ra dựa trên khuôn mẫu đó.

Một Class có thể tạo ra nhiều Object. Các Object được tạo từ cùng một Class có cùng cấu trúc nhưng dữ liệu của từng Object có thể khác nhau.

Ví dụ:

Student student1 = Student("Thương", 20);
Student student2 = Student("Tiến", 21);

Ở đây student1 và student2 là hai Object khác nhau nhưng đều được tạo từ Class Student.

Trong ứng dụng thực tế, điều này rất hữu ích vì một Class có thể được sử dụng để tạo ra rất nhiều đối tượng có cùng loại dữ liệu.

  1. Property và Method

Trong một Class, dữ liệu và hành vi thường được thể hiện thông qua Property/Field và Method.

Property/Field là những biến được khai báo bên trong Class để lưu trữ thông tin của Object.

Ví dụ một sản phẩm có thể có:

  • Tên sản phẩm
  • Giá
  • Số lượng
  • Mã sản phẩm

Đây là những dữ liệu thuộc về sản phẩm.

Method là các hàm được khai báo bên trong Class để thực hiện một hành động.

Ví dụ một sản phẩm có thể có các hành động:

  • Hiển thị thông tin
  • Tính giá
  • Cập nhật số lượng

Việc đặt dữ liệu và hành vi liên quan vào cùng một Class là một trong những đặc điểm cơ bản của lập trình hướng đối tượng.

  1. Constructor là gì?

Constructor là một phương thức đặc biệt được sử dụng để khởi tạo Object.

Khi một Object được tạo ra, Constructor được gọi để thiết lập những giá trị ban đầu cho Object.

Constructor trong Dart thường có tên giống với Class.

Ví dụ:

class Student {
  String name;
  int age;
  Student(this.name, this.age);
}

Student(this.name, this.age) là Constructor.

Khi tạo Object, các giá trị được truyền vào Constructor sẽ được sử dụng để khởi tạo dữ liệu cho Object.

Constructor rất quan trọng vì trong các ứng dụng thực tế, Object thường cần có dữ liệu ngay từ thời điểm được tạo ra.

  1. Từ khóa this

this dùng để tham chiếu đến Object hiện tại.

Nó thường được sử dụng trong Constructor hoặc Method khi cần phân biệt thuộc tính của Object với tham số hoặc biến cục bộ có cùng tên.

Ví dụ:

Student(this.name, this.age);

Ở đây this.name và this.age đại diện cho thuộc tính name và age của Object hiện tại.

Trong Dart, cách viết này rất phổ biến vì ngắn gọn và dễ đọc.

  1. Named Constructor

Dart cho phép một Class có nhiều cách khởi tạo Object thông qua Named Constructor.

Named Constructor là Constructor có thêm tên phía sau tên Class.

Mục đích của Named Constructor là cung cấp nhiều cách khác nhau để tạo Object tùy theo trường hợp sử dụng.

Ví dụ một Class có thể có Constructor thông thường để tạo User bình thường và một Named Constructor để tạo User khách.

Điều này giúp Class linh hoạt hơn khi khởi tạo Object.

  1. Factory Constructor

Factory Constructor là một dạng Constructor đặc biệt trong Dart.

Khác với Constructor thông thường, Factory Constructor có thể kiểm soát quá trình tạo Object và quyết định Object nào sẽ được trả về.

Factory Constructor có thể được sử dụng trong những trường hợp như:

  • Tạo Object theo điều kiện.
  • Trả về một Object đã tồn tại.
  • Chuyển dữ liệu thành Object.
  • Xử lý việc khởi tạo phức tạp.

Factory Constructor thường xuất hiện trong các Model, thư viện và kiến trúc ứng dụng Dart/Flutter thực tế.

Bạn chưa cần quá tập trung vào phần này ở giai đoạn đầu, nhưng nên hiểu khái niệm và biết cách nhận ra nó khi đọc code.

  1. Encapsulation – Tính đóng gói

Encapsulation hay tính đóng gói là một trong bốn tính chất quan trọng của OOP.

Đóng gói nghĩa là gom dữ liệu và các phương thức xử lý dữ liệu vào trong một Class, đồng thời kiểm soát cách các thành phần bên ngoài truy cập vào dữ liệu đó.

Mục đích của Encapsulation là:

  • Bảo vệ dữ liệu.
  • Hạn chế việc thay đổi dữ liệu không hợp lệ.
  • Kiểm soát cách dữ liệu được truy cập.
  • Giúp Class dễ quản lý hơn.

Trong Dart, tên bắt đầu bằng dấu _ được xem là private trong phạm vi Library.

Ví dụ:

double _balance = 0;

Dấu _ cho biết thành phần này không nên được truy cập trực tiếp từ bên ngoài Library.

Đóng gói không đơn giản chỉ là “ẩn biến”. Quan trọng hơn, nó giúp Class kiểm soát cách dữ liệu được sử dụng.

  1. Getter là gì?

Getter là cơ chế dùng để lấy dữ liệu từ một Object.

Getter thường được sử dụng khi một thuộc tính được đóng gói và không muốn cho bên ngoài truy cập trực tiếp vào biến bên trong.

Ví dụ:

String get name => _name;

Khi đó bên ngoài có thể lấy giá trị thông qua name thay vì truy cập trực tiếp _name.

Getter thường được sử dụng cùng với Encapsulation.

  1. Setter là gì?

Setter là cơ chế dùng để thay đổi giá trị của một thuộc tính.

Setter cho phép Class kiểm soát dữ liệu trước khi thay đổi.

Ví dụ, thay vì cho phép bên ngoài thay đổi trực tiếp số dư tài khoản, Class có thể kiểm tra xem giá trị mới có hợp lệ hay không trước khi cập nhật.

Setter thường được sử dụng khi muốn kiểm soát việc ghi dữ liệu.

  • Có thể hiểu đơn giản:
  • Getter → đọc dữ liệu
  • Setter → thay đổi dữ liệu
  1. Static là gì?

static dùng để khai báo thành phần thuộc về Class, thay vì thuộc về từng Object.

Thông thường, mỗi Object sẽ có dữ liệu riêng.

Nhưng với static, dữ liệu hoặc Method được chia sẻ ở cấp Class.

Static thường được sử dụng cho:

  • Hằng số dùng chung.
  • Các hàm tiện ích.
  • Dữ liệu chung cho tất cả Object.
  • Các chức năng không cần tạo Object để sử dụng.

Ví dụ:

class MathUtils {
  static int add(int a, int b) {
    return a + b;
  }
}

Có thể gọi trực tiếp thông qua Class mà không cần tạo Object.

  1. Inheritance – Tính kế thừa

Inheritance hay tính kế thừa là một trong bốn tính chất quan trọng của OOP.

Kế thừa cho phép một Class mới sử dụng lại những đặc điểm và hành vi của một Class đã có.

Class được kế thừa thường được gọi là Class cha, còn Class kế thừa được gọi là Class con.

Trong Dart, kế thừa được thực hiện bằng từ khóa: extends

Ví dụ:

class Dog extends Animal {
}

Điều này có nghĩa Dog kế thừa từ Animal.

Kế thừa giúp:

  • Tái sử dụng code.
  • Hạn chế việc viết lại code.
  • Xây dựng mối quan hệ giữa các Class.
  • Dễ mở rộng chương trình.

Tuy nhiên, không phải lúc nào cũng nên sử dụng kế thừa. Trong các hệ thống lớn, lập trình viên thường cân nhắc giữa Inheritance và Composition.

  1. super là gì?

super được sử dụng để tham chiếu đến Class cha.

Nó thường được sử dụng để:

  • Gọi Constructor của Class cha.
  • Gọi Method của Class cha.
  • Truy cập thuộc tính của Class cha.

Ví dụ:

class Dog extends Animal {
  Dog(String name) : super(name);
}

Ở đây super(name) gọi Constructor của Class cha.

Khi đọc code Flutter, bạn sẽ gặp super khá thường xuyên, đặc biệt trong Constructor của Widget.

  1. Method Overriding

Overriding là việc Class con viết lại cách hoạt động của một Method đã được định nghĩa ở Class cha.

Trong Dart, @override được sử dụng để đánh dấu Method đang được ghi đè.

Ví dụ:

@override
void sound() {
  print("Gâu gâu");
}

Overriding cho phép Class con thay đổi hành vi của Class cha sao cho phù hợp với mục đích của Class con.

Đây là cơ chế quan trọng để thực hiện Polymorphism.

  1. Polymorphism – Tính đa hình

Polymorphism hay tính đa hình là một trong bốn tính chất quan trọng của OOP.

Đa hình cho phép các Object thuộc những Class khác nhau có thể được xử lý thông qua một kiểu chung nhưng mỗi Object có thể thực hiện hành vi theo cách riêng.

Nói đơn giản, cùng một Method nhưng các Class khác nhau có thể có cách thực hiện khác nhau.

Ví dụ:

Animal
├── Dog → sound() → Gâu gâu
└── Cat → sound() → Meo meo

Cả Dog và Cat đều có sound() nhưng kết quả khác nhau.

Đa hình giúp chương trình linh hoạt hơn và giảm sự phụ thuộc vào một Class cụ thể.

  1. Abstraction – Tính trừu tượng

Abstraction hay tính trừu tượng là một trong bốn tính chất quan trọng của OOP.

Trừu tượng có nghĩa là chỉ tập trung vào những đặc điểm cần thiết và ẩn đi những chi tiết triển khai không cần thiết đối với người sử dụng.

Ví dụ, khi sử dụng một chiếc điện thoại, người dùng chỉ cần biết cách gọi điện, nhắn tin hoặc mở ứng dụng. Người dùng không cần biết toàn bộ quá trình xử lý bên trong điện thoại.

Trong lập trình cũng tương tự. Một Class có thể cung cấp những Method cần thiết nhưng che giấu cách các Method đó hoạt động bên trong.

Dart hỗ trợ Abstraction thông qua abstract class.

Ví dụ:

abstract class Animal {
  void sound();
}

Class trừu tượng thường được dùng để định nghĩa một cấu trúc chung cho các Class khác triển khai.

  1. Abstract Class

abstract class là Class trừu tượng.

Abstract Class thường được sử dụng để tạo ra một cấu trúc hoặc quy tắc chung cho các Class con.

Một Abstract Class có thể chứa:

  • Thuộc tính.
  • Method đã có phần triển khai.
  • Method chưa có phần triển khai.

Không thể tạo Object trực tiếp từ Abstract Class.

Ví dụ:

abstract class Animal {
  void sound();
}

Class Animal chỉ đưa ra yêu cầu rằng các Class phù hợp phải có sound(). Cách sound() hoạt động sẽ do Class cụ thể quyết định.

  1. Interface và implements

Trong Dart, mỗi Class đều có thể được sử dụng như một Interface.

Interface có thể hiểu là một bộ quy tắc mà Class khác phải tuân theo.

Từ khóa implements được sử dụng khi một Class muốn triển khai một Interface.

Ví dụ:

class Dog implements Animal {
}

Khi sử dụng implements, Class thực hiện phải tự triển khai những Method mà Interface yêu cầu.

Điểm cần nhớ:

extends → kế thừa
implements → tuân theo Interface

extends tập trung vào việc tái sử dụng cấu trúc và hành vi của Class cha, trong khi implements tập trung vào việc đảm bảo Class đáp ứng một cấu trúc hoặc hợp đồng nhất định.

  1. Mixin

Mixin là một cơ chế đặc biệt của Dart cho phép tái sử dụng hành vi giữa nhiều Class mà không cần sử dụng kế thừa trực tiếp.

Mixin được khai báo bằng từ khóa mixin và thường được sử dụng bằng with.

Ví dụ:

mixin Flyable {
  void fly() {
    print("Đang bay");
  }
}

Một Class có thể sử dụng Mixin này để có thêm hành vi fly().

Mixin hữu ích khi nhiều Class khác nhau cần cùng một hành vi nhưng những Class đó không nhất thiết phải có quan hệ kế thừa với nhau.

  1. Composition – Kết hợp đối tượng

Composition là một cách thiết kế trong OOP, trong đó một Class sử dụng hoặc chứa Object của Class khác thay vì kế thừa trực tiếp.

Có thể hiểu đơn giản:

Inheritance → "là một"
Composition → "có một"

Ví dụ:

Dog là một Animal
Car có một Engine

Composition giúp xây dựng chương trình linh hoạt vì một Class có thể sử dụng nhiều Object khác nhau mà không cần tạo ra hệ thống kế thừa phức tạp.

Trong các dự án thực tế, đặc biệt là các dự án có kiến trúc lớn, Composition thường được sử dụng rất nhiều.

  1. Null Safety trong Dart OOP

Null Safety là cơ chế của Dart giúp hạn chế lỗi xảy ra khi một biến không có giá trị.

Trong Dart, mặc định một biến không được phép nhận null.

Ví dụ:

String name;

name phải có giá trị String.

Nếu muốn cho phép null, sử dụng dấu ?:

String? name;

Điều này đặc biệt quan trọng khi xây dựng Model trong Flutter vì dữ liệu lấy từ API hoặc Database có thể thiếu một số trường.

Null Safety giúp lập trình viên phát hiện và xử lý những trường hợp có thể xảy ra null ngay trong quá trình viết code.

  1. Named Parameters và required

Dart thường sử dụng Named Parameters khi làm việc với Constructor.

Ví dụ:

class Product {
  Product({
    required this.name,
    required this.price,
  });
  String name;
  double price;
}

required có nghĩa là tham số bắt buộc phải được truyền vào khi tạo Object.

Named Parameters giúp code dễ đọc hơn vì tên của từng giá trị được thể hiện rõ ràng.

Đây là cách viết xuất hiện rất thường xuyên trong Flutter.

  1. OOP trong Flutter

Dart OOP có vai trò rất lớn trong Flutter.

Flutter sử dụng Class để xây dựng rất nhiều thành phần của ứng dụng.

Ví dụ:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text("Hello Flutter");
  }
}

Trong đoạn code này:

  • MyApp là một Class.
  • extends StatelessWidget là kế thừa.
  • @override là ghi đè Method.
  • build() là Method.
  • super thường xuất hiện trong Constructor của Widget.

Ngoài Widget, OOP còn được sử dụng trong:

  • Model.
  • Service.
  • Repository.
  • API Client.
  • State Management.
  • Database.
  • Các lớp xử lý nghiệp vụ.

Vì vậy, nếu chưa hiểu OOP thì khi đọc code Flutter sẽ rất dễ gặp tình trạng nhìn thấy nhiều class, extends, implements, override, abstract, mixin nhưng không hiểu chúng dùng để làm gì.

  1. Bốn tính chất quan trọng nhất của OOP

Trong Dart OOP, cần đặc biệt nhớ bốn tính chất chính:

  1. Encapsulation – Đóng gói
  • Đóng gói dữ liệu và hành vi vào Class, đồng thời kiểm soát quyền truy cập.
  • Mục đích: bảo vệ và kiểm soát dữ liệu.
  1. Inheritance – Kế thừa
  • Class con có thể kế thừa từ Class cha.
  • Mục đích: tái sử dụng code.
  1. Polymorphism – Đa hình
  • Các Class khác nhau có thể có cùng một Method nhưng cách thực hiện khác nhau.
  • Mục đích: giúp chương trình linh hoạt.
  1. Abstraction – Trừu tượng
  • Ẩn những chi tiết không cần thiết và chỉ cung cấp những gì cần thiết.
  • Mục đích: giảm độ phức tạp và tạo cấu trúc rõ ràng.

Có thể ghi nhớ nhanh:

  • Đóng gói → bảo vệ dữ liệu
  • Kế thừa → tái sử dụng
  • Đa hình → linh hoạt
  • Trừu tượng → ẩn chi tiết
  1. Các từ khóa Dart OOP cần nhớ

Sau khi học Dart OOP, bạn nên nhận biết được những từ khóa và khái niệm sau:

  • class
  • object
  • this
  • constructor
  • named constructor
  • factory
  • static
  • get
  • set
  • extends
  • super
  • @override
  • abstract
  • implements
  • mixin
  • with
  • required

Không cần học thuộc lòng tất cả ngay lập tức. Quan trọng nhất là khi nhìn thấy chúng trong code phải biết chúng có mục đích gì và tại sao lập trình viên sử dụng chúng.

  1. Thứ tự nên học Dart OOP

Để tránh học lan man, có thể học theo thứ tự:

Class → Object → Field → Method → Constructor → this → Named Constructor → Encapsulation → Getter/Setter → Inheritance → extends → super → Override → Polymorphism → Abstraction → abstract class → Interface → implements → Mixin → Composition → Static → Null Safety → Named Parameters → Factory Constructor

Trong đó, những phần nên hiểu thật chắc trước khi đi vào Flutter là:

Class → Object → Constructor → Encapsulation → Inheritance → Override → Polymorphism → Abstraction

Sau đó học tiếp:

implements → Mixin → Composition → Factory Constructor → Static
  1. Kết luận

Dart OOP là kiến thức nền tảng của ngôn ngữ Dart và có vai trò rất quan trọng trong quá trình phát triển ứng dụng Flutter.

Thông qua OOP, chương trình được tổ chức thành các Class và Object. Class mô tả dữ liệu và hành vi, còn Object là những đối tượng cụ thể được tạo ra từ Class.

Những kiến thức quan trọng nhất của Dart OOP gồm Class, Object, Constructor, Encapsulation, Inheritance, Polymorphism và Abstraction. Bên cạnh đó, khi làm việc với Dart và Flutter thực tế cần tiếp tục hiểu extends, implements, abstract, override, super, Getter/Setter, Mixin, Composition, Static, Factory Constructor và Null Safety.

Mục tiêu của việc học Dart OOP không phải là học thuộc định nghĩa mà là hiểu được cấu trúc của code và lý do tại sao lập trình viên tổ chức code theo cách đó. Khi đã hiểu OOP, việc đọc code Flutter sẽ dễ dàng hơn vì có thể nhận biết được Class nào đang được tạo, Class nào đang kế thừa, Method nào đang được ghi đè và các đối tượng đang liên kết với nhau như thế nào.

Đối đối với quá trình học Flutter để tham gia dự án thực tế, Dart OOP là một phần kiến thức nền tảng cần nắm chắc trước khi đi sâu vào Widget, State Management, API, Database và Architecture.

 

Bài viết khác

JSON & HTTP Status Codes

1. JSON là gì? JSON là một định dạng dữ liệu được sử dụng rất phổ biến trong lập trình, đặc biệt là khi Client và Server cần trao đổi dữ liệu với nhau. JSON có cách tổ chức dữ liệu khá đơn giản và dễ đọc. Dữ liệu thường được biểu diễn theo dạng […]

Tìm hiểu về Flutter Widget Fundamentals

  Widget trong Flutter là gì? Widget là thành phần cơ bản nhất được sử dụng để xây dựng giao diện trong Flutter. Mỗi thành phần trên màn hình như văn bản, hình ảnh, nút bấm, danh sách, khoảng cách hoặc toàn bộ một màn hình đều có thể được biểu diễn bằng Widget. Thay […]

Tìm hiểu về Isolate & Concurrency

  Isolate là gì? Trong Dart, Isolate là một vùng thực thi độc lập, có bộ nhớ riêng và Event Loop riêng. Mỗi Isolate có thể thực hiện công việc mà không trực tiếp chia sẻ bộ nhớ với Isolate khác. Có thể hiểu đơn giản: Isolate là cách Dart thực hiện các tác vụ […]

Lập trình bất đồng bộ với Future, async, await.

  Lập trình bất đồng bộ là gì? Lập trình bất đồng bộ (Asynchronous Programming) là cách tổ chức chương trình cho phép một tác vụ mất thời gian được thực hiện mà không cần chặn toàn bộ chương trình trong thời gian chờ. Trong ứng dụng thực tế, có nhiều công việc cần thời […]

Tìm hiểu về Null Safety

  Null Safety là gì? Null Safety là một cơ chế an toàn kiểu dữ liệu được Dart sử dụng để hạn chế các lỗi liên quan đến giá trị null trong chương trình. Null Safety được đưa vào Dart nhằm giúp lập trình viên xác định rõ một biến có thể chứa null hay […]

Tìm hiểu về ngôn ngữ lập trình Dart

  Dart là gì? Dart là một ngôn ngữ lập trình mã nguồn mở được phát triển bởi Google, được sử dụng để xây dựng các ứng dụng có thể chạy trên nhiều nền tảng khác nhau. Hiện nay, Dart được biết đến nhiều nhất vì đây là ngôn ngữ lập trình chính được sử […]

Leave a Reply

Your email address will not be published. Required fields are marked *